I have a subscribe form in wordpress that (currently) only has the ability to add submitted email to a custom post type (subscribers) and show it in backend.I am wondering how to also have this functionality, and send this email to a custom url (concretely to APSIS).
So I have a form
<form id="subscribe" class="subscribe_form" name="subscribe_form" action="#" method="post">
<input name="subscriber_email" class="subscriber_email" placeholder="Your mail here">
<input class="submit" type="submit" value="Submit">
</form>
My save custom post type function that gets executed via AJAX
<?php
add_action('wp_ajax_save_subscriber', 'save_subscriber');
add_action('wp_ajax_nopriv_save_subscriber', 'save_subscriber');
if (!function_exists('save_subscriber')) {
function save_subscriber() {
if (isset($_POST['subscriber_email']) && is_email($_POST['subscriber_email'])) {
global $wpdb;
$post_data = array(
'post_type' => 'subscribers',
'post_status' => 'publish'
);
$published_id = wp_insert_post( $post_data );
add_post_meta($published_id, 'subscriber_email', $_POST['subscriber_email']);
$out = 'OK';
} else{
$out = 'ERROR';
}
die($out);
}
}
And my AJAX
$('#subscribe').submit(function() {
'use strict';
var str = $(this).serialize() + '&action=save_subscriber';
var $form = $(this);
var $wrapper = $(this).parent();
$.ajax({
type: 'POST',
url: custom.ajaxurl,
data: str,
success: function(msg){
if( msg === 'OK' ) {
$form.animate({ height: '0px' }, 800, function() {
$form.hide();
});
$wrapper.find('.success_message').delay(400).html(custom.success).slideDown(600);
}else {
$wrapper.find('.subscriber_email').addClass('field_error').attr('placeholder', custom.error_mail).val('').focus();
}
}
});
return false;
});
Now I have some more wrappers, and noonce field etc. but that's not important here.
This works fine when you want to just add a post to the CPT, but I need to submit this to
http://www.anpdm.com/public/process-subscription-form.aspx?formId=xxxxxxxxxxx
I got the id and everything from the client, now I need to implement this.
I've seen something about curl, but I've never done anything with it, so I don't really know where to start. Since my action is pointing to my save_subscriber() function I recon that in that function I'd also have to add a way to send this form to the required url. But how?
Any info will help, thanks.
ANSWER
So following the answer provided by silver, I managed to get it working.
#Run CURL
$url = 'http://www.anpdm.com/public/process-subscription-form.aspx?formId=xxxxxxxxxx';
$request = curl_init();
curl_setopt_array( $request, array (
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_URL => $url,
CURLOPT_POST => 1,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13',
CURLOPT_POSTFIELDS => $custom_query_string,
));
$response = curl_exec($request);
$response_data = curl_getinfo($request);
curl_close($request);
#END CURL
if ($response_data['http_code'] == 200) {
$out = 'OK';
}
The formId is the form number specific for this user, and the $custom_query_string conformed to the form provided by APSIS and contained something like this:
pf_Email=$_POST['email']&
Submit=Prenumerera&
pf_DeliveryFormat=HTML&
pf_MailinglistName1=xxxxx&
pf_FormType=OptInForm&
pf_OptInMethod=SingleOptInMethod&
pf_CounterDemogrFields=0&
pf_CounterMailinglists=1&
pf_AccountId=xxxx&
pf_ListById=1&
pf_Version=2
After that all worked, I get my subscribers in the wordpress backend, and they appear in the APSIS console where the users are :)
I guess I needed user_agent and correct query string.
If I were you I'll just duplicate the current form with different ID and action pointing to a different URL then hide it populating it automatically based on firs form, then silently submit it on Success response of first form Ajax request,
But yeah, If you need to POST URL using CURL-PHP without any form this example code below will probably do, I hook it on your current function.
function save_subscriber() {
if (isset($_POST['subscriber_email']) && is_email($_POST['subscriber_email'])) {
global $wpdb;
$post_data = array(
'post_type' => 'subscribers',
'post_status' => 'publish'
);
$published_id = wp_insert_post( $post_data );
add_post_meta($published_id, 'subscriber_email', $_POST['subscriber_email']);
#Run CURL
$url = 'http://www.anpdm.com/public/process-subscription-form.aspx'; // URL to be Posted
$request = curl_init(); //open connection
curl_setopt_array( $request, array (
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_URL => $url,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $_REQUEST, /* Since your form is already serialize, you don't need to build query string*/
));
$response = curl_exec($request); // Execute Curl
$response_data = curl_getinfo($request); // Array of curl response info
curl_close($request); // Close Connection
#END CURL
#$out = $response; // push curl response on Ajax Submit response
$out = $response_data['http_code']; /* 200 will be the value of this for successfully curl request, you can just replace your Ajax success code with 200 instead of OK or just ignore the response, though its better to know if curl request is successful*/
} else{
$out = 'ERROR';
}
die($out);
}
Testing
$url = 'http://www.anpdm.com/public/process-subscription-form.aspx';
$request = curl_init();
curl_setopt_array( $request, array (
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_URL => $url,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => "id=noID&value=novalue",
));
$response = curl_exec($request);
$response_data = curl_getinfo($request);
curl_close($request);
print_r( $response_data );
$response_data OUTPUT
Array
(
[url] => http://www.anpdm.com/public/process-subscription-form.aspx
[content_type] => text/html; charset=utf-8
[http_code] => 200
[header_size] => 222
[request_size] => 180
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 1.546
[namelookup_time] => 0.515
[connect_time] => 0.843
[pretransfer_time] => 0.843
[size_upload] => 21
[size_download] => 13048
[speed_download] => 8439
[speed_upload] => 13
[download_content_length] => 13048
[upload_content_length] => 21
[starttransfer_time] => 1.203
[redirect_time] => 0
[redirect_url] =>
[primary_ip] => 89.234.52.177
[certinfo] => Array
(
)
[primary_port] => 80
[local_ip] => 192.168.254.8
[local_port] => 53736
)
Related
Using Wordpress, I'm attempting to access files from one out of two file inputs using $_FILES but running into some problems:
To outline - I'm using a front-end form that has two file fields, both of which accept multiple files:
<form id="form" action="" method="post">
<input type="text" name="my_name">
<input type="file" name="reference_images[]" multiple>
<input type="file" name="photo_of_area[]" multiple>
</form>
The file inputs will be taking images, and I need to upload images from "reference_images" to one repeater field, ad "photo_of_area" to another repeater field. This form is posted via AJAX using FormData - the functions for this are below:
function saveForm(varform) {
blockUI();
jQuery.ajax({
type: "POST",
url: window.ajaxObject.ajaxUrl,
dataType: "JSON",
data: varform,
processData: false,
contentType: false,
cache: false,
success: onSuccesPing(),
crossDomain:true,
});
}
jQuery('#form').submit(function(event) {
event.preventDefault(); // Prevent form submitting as normal
var formData = new FormData(jQuery('#form')[0]);
formData.append("action", "messaging_post");
saveForm(formData);
});
I then have a function handle the messaging_post action which is below, this creates a new post with the form data, and loops over the attached images and injects them to my ACF repeater:
add_action( 'wp_ajax_messaging_post', 'messaging_post' );
add_action('wp_ajax_nopriv_messaging_post', 'messaging_post');
function messaging_post(){
if(isset($_POST['my_name'])) {
$name = sanitize_text_field($_POST['my_name']);
$new_post = array(
'ID' => '',
'post_type' => 'quote_requests',
'post_status' => 'publish',
'post_title' => $title,
'post_content' => '',
);
$post_id = wp_insert_post($new_post);
$post = get_post($post_id);
update_field('name', $name, $post_id); // Updates the ACF text field 'name' for the inserted post
// Works, but uploads files from BOTH file inputs to the single ACF repeater:
foreach($_FILES as $value){
for ($i=0; $i <count($value['name']); $i++) {
$errors= array();
$file_name = $value['name'][$i];
$file_size = $value['size'][$i];
$file_tmp = $value['tmp_name'][$i];
$file_type = $value['type'][$i];
$file_ext=strtolower(end(explode('.',$value['name'][$i])));
if(empty($errors)==true) {
$wordpress_upload_dir = wp_upload_dir();
$profilepicture = $wordpress_upload_dir['path'].'/';
move_uploaded_file($file_tmp, $profilepicture.$file_name);
} else{
print_r($errors);
}
$file_name_and_location = $profilepicture.$file_name;
$file_title_for_media_library = $value['name'][$i];
$fildename = $value['name'][$i];
$arr_file_type = wp_check_filetype(basename($fildename));
$uploaded_file_type = $arr_file_type['type'];
$attachment = array(
'post_mime_type' => $uploaded_file_type,
'post_title' => addslashes($file_title_for_media_library),
'post_content' => $fildename,
'post_status' => 'inherit',
'post_parent' => 0,
'post_author' => get_current_user_id(),
);
wp_read_image_metadata( $file_name_and_location );
$attach_id = wp_insert_attachment( $attachment, $file_name_and_location,true,false);
$attach_data = wp_generate_attachment_metadata($attach_id,$file_name_and_location );
wp_update_attachment_metadata( $attach_id, $attach_data );
$images[]= array("image" => $attach_id);
}
}
update_field('photo_area', $images, $post_id);
}
}
The above works, and populates the created post with the name from the form, but this attaches files from BOTH the reference_images and photo_of_area to the photo_area ACF repeater.
When trying to access $_FILES using a function such as the following:
foreach($_FILES["photo_of_area"] as $value){
for ($i=0; $i <count($value['name']); $i++) {
$errors= array();
$file_name = $value['name'][$i];
$file_size = $value['size'][$i];
$file_tmp = $value['tmp_name'][$i];
$file_type = $value['type'][$i];
$file_ext=strtolower(end(explode('.',$value['name'][$i])));
if(empty($errors)==true) {
$wordpress_upload_dir = wp_upload_dir();
$profilepicture = $wordpress_upload_dir['path'].'/';
move_uploaded_file($file_tmp, $profilepicture.$file_name);
} else{
print_r($errors);
}
$file_name_and_location = $profilepicture.$file_name;
$file_title_for_media_library = $value['name'][$i];
$fildename = $value['name'][$i];
$arr_file_type = wp_check_filetype(basename($fildename));
$uploaded_file_type = $arr_file_type['type'];
$attachment = array(
'post_mime_type' => $uploaded_file_type,
'post_title' => addslashes($file_title_for_media_library),
'post_content' => $fildename,
'post_status' => 'inherit',
'post_parent' => 0,
'post_author' => get_current_user_id(),
);
wp_read_image_metadata( $file_name_and_location );
$attach_id = wp_insert_attachment( $attachment, $file_name_and_location,true,false);
$attach_data = wp_generate_attachment_metadata($attach_id,$file_name_and_location );
wp_update_attachment_metadata( $attach_id, $attach_data );
$images[]= array("image" => $attach_id);
}
}
update_field('photo_area', $images, $post);
This doesn't seem to work and returns nothing.
I'm assuming that after going through FormData(), the files are now not accessible on the normal $_FILES['name_of_input'], and should rather have something else done with them?
I've also tried just appending the images to the FormData, but seemed to be having the same issue.
Would anyone be able to shed some light on how I could access $_FILES["photo_of_area"], and also $_FILES["reference_images"] independently of each other after being passed through FormData()? Or any alternative ways that I should look at to achieve the desired behaviour.
Ideally, I need to access images from each file input respectively.
Thanks!
I've managed to achieve this by changing my loop over the $_FILES array as such:
$photo_of_area = $_FILES["photo_of_area"];
foreach ($photo_of_area['name'] as $key => $value) {
$errors = array();
$file_name = $photo_of_area['name'][$key];
$file_size = $photo_of_area['size'][$key];
$file_tmp = $photo_of_area['tmp_name'][$key];
$file_type = $photo_of_area['type'][$key];
$file_ext = strtolower(end(explode('.',$photo_of_area['name'][$key])));
if (empty($errors) == true) {
$wordpress_upload_dir = wp_upload_dir();
$upload_dir_path = $wordpress_upload_dir['path'].'/';
move_uploaded_file($file_tmp, $upload_dir_path.$file_name);
} else {
print_r($errors);
}
$file_name_and_location = $upload_dir_path.$file_name;
$file_title_for_media_library = $photo_of_area['name'][$key];
$fildename = $photo_of_area['name'][$key];
$arr_file_type = wp_check_filetype(basename($fildename));
$uploaded_file_type = $arr_file_type['type'];
$attachment = array(
'post_mime_type' => $uploaded_file_type,
'post_title' => addslashes($file_title_for_media_library),
'post_content' => $fildename,
'post_status' => 'inherit',
'post_parent' => 0,
'post_author' => get_current_user_id(),
);
wp_read_image_metadata( $file_name_and_location );
$attach_id = wp_insert_attachment( $attachment, $file_name_and_location,true,false);
$attach_data = wp_generate_attachment_metadata($attach_id,$file_name_and_location );
wp_update_attachment_metadata( $attach_id, $attach_data );
$area_photos_array[] = array("image" => $attach_id);
}
update_field('photo_area', $area_photos_array, $post_id);
This successfully injects each image uploaded to a new row of the photo_area repeater inside the current post specified by $post_id.
I have a custom post type built in WordPress named Knowledge.
Knowledge currently only has 4 posts in total. By default, 3 posts are shown, then on load more click, I want the last, 4th blog card to show.
However, currently, my AJAX request isn't succeeding, it gives me the /wp-admin/admin-ajax.php 403 (Forbidden) error. Similar questions stated that it might be related to security plugins. However, I have disabled any security related plugins (Jetpack) and the error still exists.
Here is my approach so far:
knowledge-listing.php
<?php
global $post;
$args = array(
'post_type' => 'knowledge',
'posts_per_page' => 3,
'post_status' => 'publish',
'orderby' => 'publish_date',
'order' => 'DESC'
);
$query = new WP_Query($args);
if ($query->have_posts()):
while ($query->have_posts()):
$query->the_post();
get_part('templates/snippets/knowledge-card', array(
'heading' => get_the_title() ,
'subheading' => get_the_excerpt() ,
'background' => wp_get_attachment_url(get_post_thumbnail_id($post->ID)) ,
));
endwhile;
wp_reset_postdata(); ?>
<div class="knowledgeListing__loadmore">
<a href="#" id="loadmore" class="button--loadmore" data-type="knowledge" data-max-num-pages="<?php echo $query->max_num_pages; ?>">
<?php echo _e('Load More', 'theme'); ?>
</a>
</div>
<?php
endif; ?>
loadmore.js
jQuery(function($){
$(document).ready(function(){
$("#loadmore").on('click', function (e) {
e.preventDefault();
var btn = $(this);
showNextItems(btn);
});
function showNextItems(btn) {
var max_num_pages = btn.data('max-num-pages');
var post_type = btn.data('type');
var button = btn,
data = {
'action':'loadmore',
'query': loadmore_params.posts,
'page' : loadmore_params.current_page,
// 'security' : loadmore_params.security,
// 'max_num_pages' : max_num_pages,
// 'post_type' : post_type
};
$.ajax({
url : loadmore_params.ajaxurl,
data : data,
type : 'POST',
beforeSend : function ( xhr ) {
button.text('Loading...');
},
success : function( data ){
if( data ) {
button.text( 'Load More' ).prev().before(data);
loadmore_params.current_page++;
$('.knowledgeListing__wrapper').find('.knowledgeCard').last().after( data );
if ( loadmore_params.current_page == max_num_pages ){
button.remove();
}
console.log("success");
} else {
button.remove();
}
},
error : function(error){
button.text( 'Load More' );
console.table("Data: " + data);
console.table("loadmore_params: " + loadmore_params);
// console.log(error);
}
});
}
});
});
The following two console.log's spit out [object Object]
console.table("Data: " + data);
console.table("loadmore_params: " + loadmore_params);
Unsure where things are going wrong?
Edit:
console.log("Data:", data) and console.log("loadmore_params:", loadmore_params); results below:
On further inspection, when trying to access the /wp-admin/admin-ajax.php url, I see a 0. When searching for this online, it has been suggested to use die(). However, when I've added die() to the end of knowledge-listing.php, it still shows me a 0.
Here is my localized script for reference:
global $wp_query;
wp_localize_script( 'theme', 'loadmore_params', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'posts' => json_encode( $wp_query->query_vars ),
'current_page' => get_query_var( 'paged' ) ? get_query_var('paged') : 1,
'max_page' => $wp_query->max_num_pages,
'security' => wp_create_nonce("load_more")
) );
And actions:
add_action('wp_ajax_loadmore', 'pagination_ajax_handler'); // wp_ajax_{action}
add_action('wp_ajax_nopriv_loadmore', 'pagination_ajax_handler'); // wp_ajax_nopriv_{action}
Just my 2 cents but "loadmore" as an action name is quite common and may be used by some other plugins/theme function. You should really consider switching to something namespaced like wp_ajax_mypluginname_loadmore.
That said, another common issue is that you perform the add_actions too late or maybe they never get hit by code before wp-admin-ajax does his thing.
Please be 100% you hit the add_actions BEFORE the code enter wp-admin-ajax.
To make a quick test you could move those line (included the function) in your child-theme functions.php file
I'm using the master card checkout.js method version 57.
There are two types of payments ways.
I want to use only showLightbox() but unfortunately completeCallback() function is not working.
I have tried to find solution but everyone is suggesting to send Interaction.returnUrl parameter in session request but I don't want redirection.
Here is my code,
<script src="https://dohabank.gateway.mastercard.com/checkout/version/57/checkout.js"
data-error="errorCallback"
data-cancel="cancelCallback"
data-beforeRedirect="beforeRedirect"
data-afterRedirect="afterRedirect"
data-complete="completeCallback"
></script>
function completeCallback(resultIndicator, sessionVersion) {
alert(resultIndicator);
}
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://dohabank.gateway.mastercard.com/api/rest/version/57/merchant/TESTDB95810/session",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "{\r\n \"apiOperation\": \"CREATE_CHECKOUT_SESSION\",\r\n \"interaction\": {\r\n \"operation\": \"PURCHASE\"\r\n },\r\n \"order\" : {\r\n \"amount\" : \"5.10\",\r\n \"currency\" : \"QAR\",\r\n \"description\": \"Ordered goods\",\r\n \"id\": \"5\"\r\n }\r\n}",
CURLOPT_HTTPHEADER => array(
"authorization: Basic Auth Token",
"cache-control: no-cache"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
// if ($err) {
// echo "cURL Error #:" . $err;
// } else {
// echo $response;
// }
// echo $response;
$object = json_decode($response);
$sessionId = $object->{'session'}->id;
//$sessionSuccess = $object->{'successIndicator'};
//echo $sessionId;
echo $sessionId;
I Found the solution. MerchantId was missing in **Checkout.configure()** method.
I use the following snippet to create a WordPress post via the REST API, using the Node.js wrapper:
var wp = new WPAPI({
endpoint: 'http://your-site.com/wp-json',
username: 'someusername',
password: 'password'
});
wp.posts().create({
title: 'Your Post Title',
content: 'Your post content',
status: 'publish',
meta: { "custom_field": "my custom field value" }
}).then(function( response ) {
console.log( response.id );
})
When fetching the posts, the meta is empty.
Why is that and how can I fix that?
For some reason that did not work for me either. I ended by using a WordPress REST hook.
In functions.php I added:
add_filter( 'pre_post_update' , function ( $post_id , $post ) {
$body = json_decode(file_get_contents('php://input'), true);
$meta_fields = $body["meta"];
foreach ($meta_fields as $meta_key => $value) {
update_post_meta($post_id, $meta_key, $value);
}
}, '99', 2 );
The snippet above will parse the meta field and will update the post metadata fields.
If you want to include the custom fields in the responses, you can use:
//Get custom fields via Rest API
add_action( 'rest_pre_echo_response', function( $response, $object, $request ) {
//* Get the post ID
$post_id = $response[ 'id' ];
if ($response['type'] !== 'post' && $response['type'] !== 'page') return $response;
$response['custom_fields'] = get_post_meta($post_id);
return $response;
}, 10, 3 );
I'm trying to make a "meal" in my DB, so in my website i made a form with a name, and a picture. This is the code of the form :
<?php
$new_meal_title = htmlentities($_POST["new_meal_title"]);
$new_meal_img = htmlentities($_POST["new_meal_img"]);
$data = array(
'new_meal_title' => $new_meal_title,
'new_meal_img' => base64_encode($new_meal_img)
);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents(constant("API_URL")."/meal", false, $context);
if($result === FALSE){
var_dump($result);
}
$json = json_decode($result);
if($json->success == "true"){
header('Location: ../../');
return;
}
else{
echo $json->message;
}
header('Location: ../../');
?>
The form is sending data to my Node API. My Question is, how to save into a folder the image path through form in Javascript after it has been received in JSON.
Thanks for your help, i just had to change this line :
$new_meal_img = htmlentities($_POST["new_meal_img"]);
By
$new_meal_img = $_FILES['new_meal_img']["tmp_name"];
And
'new_meal_img' => base64_encode($new_meal_img)
By
'new_meal_img' => base64_encode(file_get_contents($new_meal_img))