WP / Elementor Intercept Form and Redirect with Data - wordpress

I have a form built in Elementor that I am looking to intercep, process the data and forward onto a third party then subsequently show the data on a "confirm" card.
I am able to build this whole process as a single page, setting each as display none with CSS then showing / hiding with JS as I receive AJAX responses. This isn't ideal as it breaks with JS turned off.
I haven't been able to find the right Elementor hook and way to populate a new page with PHP, has anyone had experience with this?

There are a few methods to POST data to another url from an Elementor web form.
One is using many of the API integrations such as Mailchimp, ActiveCampaign, Zapier etc. (see https://docs.elementor.com/article/281-form-faq) and (https://docs.elementor.com/category/405-integrations)
Another (very limited method) is by using the form's Action after Submit and choosing "redirect" and then using each field's short code as individual data strings in the url such as:
mysite.com/thank-you?fname=[field id="fname"]&lname=[field id="lname"]
You can even build your /thank-you/ page in Elementor to GET that data and populate Elementor elements such as text, title, links etc with the form field data. For example, I could drop a text element on the /thank-you/ page and choose dynamic instead of typing in the text area and from the dynamic drop down, choose "request parameter" and for the "type" choose GET and for the param name use your unique url keys such as fname, lname etc. You can even set prefix, suffix and even fallback text along with it.
Lastly, here is a write up on how to back end code passing data externally (https://developers.elementor.com/forms-api/#Form_New_Record_Action).
// A send custom WebHook
add_action( 'elementor_pro/forms/new_record', function( $record, $handler ) {
//make sure its our form
$form_name = $record->get_form_settings( 'form_name' );
// Replace MY_FORM_NAME with the name you gave your form
if ( 'MY_FORM_NAME' !== $form_name ) {
return;
}
$raw_fields = $record->get( 'fields' );
$fields = [];
foreach ( $raw_fields as $id => $field ) {
$fields[ $id ] = $field['value'];
}
// Replace HTTP://YOUR_WEBHOOK_URL with the actuall URL you want to post the form to
wp_remote_post( 'HTTP://YOUR_WEBHOOK_URL', [
'body' => $fields,
]);
}, 10, 2 );
And a thread with many more examples integrating with different APIs using that template as a primer (https://github.com/elementor/elementor/issues/2397)

Related

Woocommerce - Remove fields from woocommerce_form_field including validation

I am trying to customise the Woocommerce myaccount page, in particular the edit address page.
I want to display both the shipping + billing address forms on a single page. Ideally, in a single form with a one save button. I also need to remove a lot of the fields, so that it's a much simpler form of just an address (no name, company, etc).
I have implemented the code found on This Answer. It works nicely in that it shows both forms. However, I cannot remove the fields from the forms. If I try code like this:
add_filter( 'woocommerce_billing_fields' , 'custom_override_billing_fields' );
add_filter( 'woocommerce_shipping_fields' , 'custom_override_shipping_fields' );
function custom_override_billing_fields( $fields ) {
unset($fields['billing_country']);
unset($fields['billing_company']);
unset($fields['billing_first_name']);
unset($fields['billing_last_name']);
unset($fields['billing_phone']);
unset($fields['billing_email']);
return $fields;
}
function custom_override_shipping_fields( $fields ) {
unset($fields['shipping_country']);
unset($fields['shipping_company']);
unset($fields['shipping_first_name']);
unset($fields['shipping_last_name']);
return $fields;
}
It doesn't work, the fields are no longer shown but the form does not save on click... it just redirects to /my-account/edit-address/billing/ - and doesn't save. (the same form shown on this page doesn't save either).
I've also tried:
foreach ( $billing_fields as $key => $field ) :
if($key != 'billing_first_name' && $key != 'billing_last_name') :
woocommerce_form_field( $key, $field, $userMeta[$key][0] );
endif;
endforeach;
This removes the field from displaying, BUT the validation still exists - and any filter code I add to functions using
woocommerce_checkout_fields to remove the validation doesn't seem to affect this form at all.
Is there a way to either:
Remove fields from this form generated by woocommerce_form_field including the validation?
Create a custom form that allows me to set the input fields manually in the code, and update any fields that are there, ignoring the validation from Woocommerce completely?
This should work 100%. You need to state whether the fields you are removing is from billing or shipping and this is done by adding the ['billing'] or ['shipping'], whichever it is.
After this, adding the function directly to woocommerce_checkout_fields will apply both for billing and shipping.
For phone and company fields you can disable it in admin panel itself, do it.
Edit: And yes, all validation that was involved with the fields in the past will be removed. You can then apply any validation you need.
add_filter( 'woocommerce_checkout_fields' , 'brandimagemarketer_remove_billing_fields_checkout' );
function brandimagemarketer_remove_billing_fields_checkout( $fields ) {
unset($fields['billing']['billing_country']);
unset($fields['billing']['billing_first_name']);
unset($fields['billing']['billing_last_name']);
unset($fields['billing']['billing_email']);
unset($fields['shipping']['shipping_country']);
unset($fields['shipping']['shipping_first_name']);
unset($fields['shipping']['shipping_last_name']);
unset($fields['shipping']['shipping_email']);
return $fields;
}

How to prevent WordPress Media Library from removing image?

I have a custom post type that must have its feature image. Its feature image also appears in the Media Library where user can delete the image/attachment file permanently. But I want to prevent user from deleting the feature image of my custom post type. So I use the following hook to intercept the ajax request, validate if user is deleting the image of my custom post type and stop the process by using wp_die().
add_filter('pre_delete_attachment', 'check_my_custom_post_type', 0, 2);
function check_my_custom_post_type($delete, $post) {
if (Yes it is image of my custom type) {
wp_die('My message', 'My title', ['response' => 400]);
}
}
It works fine on the server side. The image of my custom post type cannot be deleted. But Media Library, on the client side, still removes the image from its views even the image on the server side has not been deleted and an exception 400 has been thrown.
How to prevent Media Library from removing images from its views on the client side if image has not been deleted on the server side?
In documentation second parameter is bool|null. Try to return false instead of wp_die
You can remove the delete link totally using the wp_prepare_attachment_for_js hook.
function remove_media_delete_link_in_grid_view( $response ) {
$response['nonces']['delete'] = false;
return $response;
}
add_filter( 'wp_prepare_attachment_for_js', 'remove_media_delete_link_in_grid_view' );
This works also with the "Bulk Delete" action. If the attachment has this nonce value false, it will not be deleted with the other bulk selected attachments 👍🏻.
But this works only with the Grid View that uses the wp_prepare_attachment_for_js hook. The List view doesn't use any Javascript. So, to prevent deleting media files in the List view, you have to:
Remove the individual delete link of each media item in the list using the media_row_actions hook.
And remove the delete option from the bulk actions menu using the bulk_actions-{$screen} hook.
function remove_media_delete_link_in_list_view( $actions ) {
unset( $actions['delete'] );
return $actions;
}
add_filter( 'media_row_actions', 'remove_media_delete_link_in_list_view' );
add_filter( 'bulk_actions-upload', 'remove_media_delete_link_in_list_view' );

How to hide a content on WordPress after receiving a certain number of views

How can I hide content in a post or page after it has received a certain amount of views I have set using a shortcode in WordPress?
Let's say I make a post. I enclose some content in the shortcode. I set the content to be shown for just 500 views. Then once the post reaches 500 views, the content should disappear from the post or page.
I have tried so many other plugins but couldn't find any solutions to this. wp-limit-post-views plugin also didn't solve my problem. I need help on this.
You could try something like that:
function hide_contents_function($atts, $content) {
$attributes = shortcode_atts(
array(
'count' => 500
),
$atts
);
// Get the max counts for the current post from the DB.
// You could use either an options if the counter is global, or the post meta.
// For this example I am using options, but it's up to you the implementation
$total_count = get_option('total_count', 0);
// Alternative way using post meta to get the counter per page/post
$total_count = get_post_meta(get_the_ID(), 'post_view_count', true);
if ( ! $total_count ) {
$total_count = 0;
}
// If the count loaded from the DB is bigger than the count
// property value then return nothing.
if ( $total_count > (int)$attributes['count'] ) {
return '';
}
return do_shortcode($content);
}
add_shortcode('hide_contents', 'hide_contents_function');
The above code, will register a short code that accepts an attribute allowing you to control how many views you want to have before you hide the contents.
In this example I used a single value from options table, but you are free to use any method you like to count the total views of a single post.
To use this short code you can do something like that:
[hide_contents count="345"]I will be hidden after 345 views.[/hide_contents]
Note that if you have installed any cache system, your content will not be hidden if the page is cached! That's not a problem of the short code, but the problem will occur because of the cache.
Finally, remember to update the counter of the views on each post refresh :)

Add multiple custom post type in URL

I've made a WordPress website people can rent cars from brokers. So I have 2 custom post types:
broker
car
There are about 10 different cars on the website. All these cars are for each broker exactly the same.
So I've created a page template page-brokers.php that lists all the brokers.
If you click on a broker, you go to the detail page of the broker single-broker.php
The URL is saferental.be/broker/broker-name
On the detail page of the broker, you'll see all the 10 different cars. If you click on a car, you go to the car detail page, which is single-car.php
The URL is saferental.be/car/car-name
At the bottom of the car detail page, is a form to contact the broker you've selected previously. As you see in the URL, there is nothing mentioned of the selected broker.
When you select a broker, its information is saved in a session and pushed into hidden fields in the form.
Everything works perfectly:
- You select a broker
- You pick a car -> go to the car detail page
- Submit the car detail page form which sends the information to the selected broker.
The result I want to have:
- If you select a broker, you go to the detail page saferental.be/broker/broker-name/ (this is already okay)
- If you select a car, you go to the car detail page which should be something like this: saferental.be/broker/broker-name/car/car-name
Test website:
http://safelease.houston-1.hybridmedia.be/
The brokers are at the bottom of the homepage.
Do you want to keep that car detail page also will available under saferental.be/car/car-name?
If not, so — just put car detail page as child page to broker and url for this page will be saferental.be/broker/broker-name/car/car-name
If you want to many different urls for the same page — try to use this plugin https://wordpress.org/plugins/mapping-multiple-urls-redirect-same-page/
I have done something similar to this myself.
This would go in your functions file:
// Setup rewrite rules something like http://yourdomain.com/broker/my-broker/car/my-car
add_action( 'init', 'rewrites_init' );
function rewrites_init() {
add_rewrite_rule(
'broker/([-a-zA-Z0-9]+)/car/([-a-zA-Z0-9]+)$',
'index.php?broker=$matches[1]&car=$matches[2]',
'top' );
}
// Add variables
add_filter('query_vars', 'add_query_vars', 0);
function add_query_vars($vars) {
$vars[] = 'broker';
$vars[] = 'car';
return $vars;
}
// catch the request for this page
add_action('parse_request', 'parse_requests', 0);
function parse_requests() {
global $wp, $wp_query;
if(isset($wp->query_vars['broker']) && isset($wp->query_vars['car'])) {
// find the car post
$posts = new WP_Query( array(
'post_type' => 'car',
'name' => $wp->query_vars['car'],
'post_status' => 'publish'
));
if(!empty($posts) ) {
// set the global query or set your own variable
$wp_query = $posts;
// set the broker variable to use in your template
$broker = get_page_by_path( $wp->query_vars['broker'], OBJECT, 'broker' );
// include your custom post type template
if (include(locate_template('single-car.php', true))) {
exit();
}
} else {
// handle error
$wp_query->set_404();
status_header(404);
locate_template('404.php', true);
exit;
}
}
}
Then in your car template, you should be able to access the $broker post variable.
After you have setup your rewrite rules, you may need to go to Admin -> Settings -> Permalinks and save to set the rewrites.
Hopefully this helps you.

Drupal Views2 Exposed Form how to change

I have a View with an exposed form . I am trying to a few things on it. Ideally I would like to have a dropdown that fires the form with no button. If that is not possible then I would like to have the button text something different than apply.
I hacked it for now and change views_form in views.module but that does not seem like the right way to do it. I only have one exposed form right now, but what if I add more?
Please see http://www.wiredvillage.ca/News for my example.
I am poking around drupal.org and seeing others with the same problem but no solutions so far. Not sure where the best place to get Drupal help is.
Here is the change I made so far:
function views_exposed_form(&$form_state) {
// Make sure that we validate because this form might be submitted
// multiple times per page.
$form_state['must_validate'] = TRUE;
$view = &$form_state['view'];
$display = &$form_state['display'];
$form_state['input'] = $view->get_exposed_input();
// Let form plugins know this is for exposed widgets.
$form_state['exposed'] = TRUE;
$form['#info'] = array();
if (!variable_get('clean_url', FALSE)) {
$form['q'] = array(
'#type' => 'hidden',
'#value' => $view->get_url(),
);
}
// Go through each filter and let it generate its info.
foreach ($view->filter as $id => $filter) {
$view->filter[$id]->exposed_form($form, $form_state);
if ($info = $view->filter[$id]->exposed_info()) {
$form['#info']['filter-' . $id] = $info;
}
}
// I CHANGED The VALUE OF THIS SUBMIT BUTTON TO GO
$form['submit'] = array(
'#name' => '', // prevent from showing up in $_GET.
'#type' => 'submit',
'#value' => t('go'),
);
$form['#action'] = url($view->get_url());
$form['#theme'] = views_theme_functions('views_exposed_form', $view, $display);
$form['#id'] = views_css_safe('views_exposed_form-' . check_plain($view->name) . '-' . check_plain($display->id));
// $form['#attributes']['class'] = array('views-exposed-form');
// If using AJAX, we need the form plugin.
if ($view->use_ajax) {
drupal_add_js('misc/jquery.form.js');
}
views_add_js('dependent');
return $form;
}
Or, you could use a preprocess function to alter the form even before it is build. I wanted to change the text on the button, so I did this:
function MYTHEME_preprocess_views_exposed_form(&$vars, $hook) {
// only alter the jobs search exposed filter form
if ($vars['form']['#id'] == 'views-exposed-form-jobs-search-page-1') {
// Change the text on the submit button
$vars['form']['submit']['#value'] = t('Search');
// Rebuild the rendered version (submit button, rest remains unchanged)
unset($vars['form']['submit']['#printed']);
$vars['button'] = drupal_render($vars['form']['submit']);
}
}
If you want the drop-down to fire, I'd use JavaScript instead of hacking the module as Eaton suggests.
Basically, you can modify the text with hook_form_alter as Eaton suggests, then use in the same hook_form_alter, add a call to drupal_add_js with your custom JS which hides the button and submits the form on the onChange handler of the select drop-down. You want that submit button there for those 10% of users for whom the JS fails.
Both of the above are fine but I found out that altering the form might not always lead to desirable results, mainly because exposed filters are themed using a specifc theme template. The proper way of changing the theme would be to override the views-exposed-form.tpl file in your theme's folder. Bear in mind that this will apply to all exposed filter forms, to theme a specific one, you will need to use a different name for that filename, like:
views-exposed-form--TITLE--DISPLAY.tpl.php
views-exposed-form--TITLE.tpl.php
and some others, you can check the Theme: Information section of your views for template naming conventions.
This module provides an auto-submit among other things http://drupal.org/project/views_hacks
This module is great to improving exposed filters http://drupal.org/project/better_exposed_filters
You should be able to use hook_form_alter() (http://api.drupal.org/api/function/hook_form_alter) to change the form as it's built, modifying the fields in question when that particular view is being displayed. You can nuke the submit button, add a #theme function that calls the drupal_add_js() function, and so on.
As long as the GET params come in the way views expect them, everything will work fine -- it was designed that way to allow bookmarking of pages with exposed filter settings, etc. The important part is to make sure you're doing the form mangling in your own module's hook_form_alter() function, so that it won't make other views driven stuff choke.

Resources