Gravity Form Shortcode Confirmation - gravity-forms-plugin

Hi I am echoing a shortcode of a gform but I need to check what the confirmation message is programmatically in php to call a function if successful and another if failed. Is it possible?

The confirmation message to be used is stashed in the GFFormDisplay::$submission property when the submission is processed so it can be retrieved when the form shortcode or block is processed on page render. You can access it like so:
$confirmation = rgars( GFFormDisplay::$submission, $form_id . '/confirmation_message' );
Alternatively you could use the gform_confirmation filter to override the confirmation to be used when the submission is being processed, before it is added to the GFFormDisplay::$submission property e.g.
add_filter( 'gform_confirmation', function ( $confirmation, $form, $entry ) {
if ( empty( $entry ) || rgar( $entry, 'status' ) === 'spam' ) {
// Return the default confirmation for spam.
return $confirmation;
}
// Check your condition here and replace the $confirmation if needed.
return $confirmation;
}, 11, 3 );

Related

Specific content for orders with custom meta_key in the WooCommerce On-hold customer email [duplicate]

Based on the following code
Add a custom checkbox in WooCommerce checkout which value shows in admin edit order
I tried to add my_field_name to order confirmation email. As I understand I have to use woocommerce_email_customer_details.
So I came to this solution, unfortunately without the desired result.
add_action('woocommerce_email_customer_details','woocommerce_email_order_invoice_number', 28, 4 );
function woocommerce_email_order_invoice_number( $order, $sent_to_admin, $plain_text, $email ) {
if( $my_field_name = get_post_meta( $order->get_id(), 'my_field_name', true ) )
echo '<p><strong>My custom field: </strong> <span style="color:red;">Is enabled</span></p>';
}
You have some minor mistakes, via the if condition "$email->id == ..."
you can target the mails
How to target other WooCommerce order emails
'customer_completed_order'
'customer_processing_order'
'customer_on_hold_order'
'customer_refunded_order'
'customer_reset_password'
'customer_invoice'
'customer_new_account'
'customer_note'
'cancelled_order'
'failed_order'
'new_order'
function woocommerce_email_order_invoice_number( $order, $sent_to_admin, $plain_text, $email ) {
// For 'new order'
if ( $email->id == 'new_order' ) {
// Get post meta
$my_field_name = get_post_meta( $order->get_id(), 'my_field_name', true );
// True and equal to
if ( $my_field_name && $my_field_name == 1 ) {
echo '<p><strong>My custom field: </strong> <span style="color:red;">Is enabled</span></p>';
}
}
}
add_action( 'woocommerce_email_customer_details', 'woocommerce_email_order_invoice_number', 20, 4 );

WooCommerce New order email notification only if order status is processing or partially_paid (multiple order status)

I have tried everything, but can't seem to get this right.
I'm using the code from Disable WooCommerce New order email notification if order status is On hold
to only send New order email (admin) when order status is processing. But I want to include a second order status "partially_paid" (coming from at deposit plugin)
My code is:
add_filter( 'woocommerce_email_recipient_new_order', 'disable_new_order_for_on_hold_order_status', 10, 2 );
function disable_new_order_for_on_hold_order_status( $recipient, $order = false ) {
if ( ! $order || ! is_a( $order, 'WC_Order' ) )
return $recipient;
return $order->get_status() === 'processing, partially_paid' ? $recipient : '';
}
I have also tried with:'
return $order->get_status() === array('processing', 'partially_paid') ? $recipient : '';
None of them working.
Any help is highly appreciated.
Thanks.
In your first attempt you are checking a single string against the order status. And there is no such status as processing, partially_paid.
To check multiple values you can use an array like you did in your second attempt. But at the moment your are checking if the current order status is equal to the full array. Instead you will have to check if the current order status is in your array. Which you can do with the in_array() function.
return in_array( $order->get_status(), array( 'processing', 'partially_paid' ) ) ? $recipient : '';
You can boil down the filter to the following code:
add_filter( 'woocommerce_email_recipient_new_order', function( $recipient, $order, $email ) {
return in_array( $order->get_status(), array( 'processing', 'partially_paid' ) ) ? $recipient : '';
}, 10, 3 );

Elementor form custom webhook returns "error" message

I'm using Elementor form with custom webhook but every time I submit it, I just get "error" message.
In my functions.php file I've got Form New Record Action according Forms API documentation.
// A send custom WebHook
add_action( 'elementor_pro/forms/new_record', function( $record, $handler ) {
$form_name = $record->get_form_settings( 'form_name' );
if ( 'test_form' !== $form_name ) {
return;
}
$raw_fields = $record->get( 'fields' );
$fields = [];
foreach ( $raw_fields as $id => $field ) {
$fields[ $id ] = $field['value'];
}
wp_remote_post( 'https://example.com', [
'body' => $fields,
]);
}, 10, 2 );
I have "wp_remote_post" there with URL I want to post the form to, but it does not redirect me or something, just returning "error" message.
On Elementor editor I added Webhook action after form submission
What could be wrong? Thanks
In the last example you need to fill in the wbbhook field at the appropriate URL
webhookfield
I had a similar error and it turned out it was a timeout.
By default, the timeout is set to only 5 seconds. This can be increased by using an add_filter in PHP. For example, if you are using make.com as the webhook, you can specify:
add_filter('http_request_timeout', function($timeout, $url = '') {
$start_with = 'https://hook.us1.make.com';
//return is_string($url) && str_starts_with($url, $start_with) // PHP 8
return is_string($url) && strncmp($url, $start_with, strlen($start_with)) === 0 // PHP 7 or older
? 30 // TODO: set appropriate timeout, WordPress default is 5 seconds
: $timeout; // return unchanged url for other requests
}, 10, 2);
This was the original issue I logged.
https://github.com/elementor/elementor/issues/20452

How to use Gravity Forms gform_validation to ensure at least one of email or phone are entered

I'm a designer rather than a developer.
I'm using Gravity Forms. I have a simple Gravity Form:
[name]
[phone]
[email]
[message]
I'd like to ensure at least one of [phone] or [email] have been entered, rather than requiring both to be filled in.
Gravity Forms support say I can use gform_validation but I don't know how to build the code to validate the form such that if both [phone] and [email] are empty a message is displayed: please enter either phone or email.
Help appreciated.
In my opinion, it might be easier to do it this way:
Verify that one of phone or email inputs is filled by submitting the input data to a script. It could be JS or a PHP script. This can be done easily by using logical operators to check if both are empty.
Then use https://www.gravityhelp.com/documentation/article/gform_validation/#2-send-entry-data-to-third-party
For a singular form, using ID's to require atleast 1 of 2 fields being filled
This works great on smaller sites who only have 1 Gravity Form with an email field and phone field. Easily customizable. Most of the code is explained with comments.
<?php
// 1 = ID of form
add_filter( 'gform_validation_1', 'custom_validation' );
function custom_validation( $validation_result ) {
$form = $validation_result['form'];
// Our desired input fields
$phone = rgpost( 'input_6' );
$email = rgpost( 'input_7' );
// Fields that must be empty
if ( empty( $phone ) && empty( $email )) {
// Looping through the fields
foreach( $form['fields'] as &$field ) {
// Finds the field with ID of 7
// This is the field where the validation message will appear, can add multiple inbetween with ||-operator
if ( $field->id == '7' /*|| $field->id == '6'*/ ) {
$field->failed_validation = true;
$field->validation_message = 'Please enter either an email address or phone number.';
$validation_result['is_valid'] = false;
}
}
}
// Assign modified $form object back to the validation result
$validation_result['form'] = $form;
return $validation_result;
}
?>
Dynamic script that will run on all forms with input type="email" & input type="tel"
This works great on larger sites with multiple Gravity Forms. The script below will affect all Gravity Forms. Code is explained with comments.
<?php
add_filter( 'gform_validation', 'custom_validation' );
function custom_validation( $validation_result ) {
$form = $validation_result['form'];
// Finds current page
$current_page = rgpost( 'gform_source_page_number_' . $form['id'] ) ? rgpost( 'gform_source_page_number_' . $form['id'] ) : 1;
// Initiated when $current_page is true
if ( $current_page ) {
// Loops through all fields
foreach( $form['fields'] as &$field ) {
// Input types
$field_phone = $field["type"] == 'phone';
$field_email = $field["type"] == 'email';
// Accessing field value with rgpost()
$field_value = rgpost("input_{$field['id']}");
if ( $field_phone ) {
// Assigning the field value of field type phone
$field_phone_type = $field_value;
}
if ( $field_email ) {
// Assigning the field value of field type email
$field_email_type = $field_value;
// Only runs if theres both a field type email AND field type phone
if (isset( $field_email_type ) && isset( $field_phone_type )) {
// If both the email and phone fields are empty
if ( empty( $field_phone_type ) && empty( $field_email_type )) {
// Validation message is applied to $field_email field only - can be modified to be both
$validation_result['is_valid'] = false;
$field->failed_validation = true;
$field->validation_message = 'Please enter either an email address or phone number.';
}
}
}
}
}
// Assign modified $form back to the validation result
$validation_result['form'] = $form;
return $validation_result;
}
?>

Drupal - Include more than one user_profile_form on a page

Edit:
I think it is because the action is the same or something. I tried to modify the action using this:
function mytheme_user_profile_form($form) {
global $user;
$uid = $user->uid;
//print '<pre>'; print_r($form); print '</pre>';
$category = $form['_category']['#value'];
switch($category) {
case 'account':
$form['#action'] = '/user/'.$uid.'/edit?destination=user/'.$uid;
break;
case 'education':
$form['#action'] = '/user/'.$uid.'/edit/education?destination=user/'.$uid;
break;
case 'experience':
$form['#action'] = '/user/'.$uid.'/edit/experience?destination=user/'.$uid;
break;
case 'publications':
$form['#action'] = '/user/'.$uid.'/edit/publications?destination=user/'.$uid;
break;
case 'conflicts':
$form['#action'] = '/user/'.$uid.'/edit/conflicts?destination=user/'.$uid;
break;
}
//print '<pre>'; print_r($form); print '</pre>';
//print $form['#action'];
$output .= drupal_render($form);
return $output;
}
But, the form action, when the form is actually rendered is unchanged. They're all /user/%uid
Can I modify the form action?
I am including several different "categories" of the user profile form on one page, and the code will correctly output the forms I'm specifying. Each form is in a separate collapsible div.
My problem is twofold.
(1) The existing values for the fields aren't pre-populated and
(2) Clicking on "Save" for one section will result in a warning: Email field is required, regardless of which form you're actually saving
I am pretty sure that for problem #2, it is because the name of the button is the same in all cases, as is the form id.
print '<h3>– Account Settings</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'account'));
print '</div>';
print '<h3>– My Info</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'Personal'));
print '</div>';
print '<h3>– Experience</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'experience'));
print '</div>';
print '<h3>– Education</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'education'));
print '</div>';
Problem #1: ? Could you post the html source?
For problem #2:
OK, I'll step through the code here:
The validation handler for the user profile form (user_profile_form_validate()) calls
user_module_invoke('validate', $form_state['values'], $form_state['values']['_account'], $form_state['values']['_category']);
Which looks like
<?php
/**
* Invokes hook_user() in every module.
*
* We cannot use module_invoke() for this, because the arguments need to
* be passed by reference.
*/
function user_module_invoke($type, &$array, &$user, $category = NULL) {
foreach (module_list() as $module) {
$function = $module .'_user';
if (function_exists($function)) {
$function($type, $array, $user, $category);
}
}
}
?>
So, the validation handler for this form is going through every module looking for user hook functions and calling them with $type = 'validate'. (Note that 'category' param is optional here - contrib modules are not required to use it)
Let's look at user.module's user hook as an example to see what happens:
function user_user($type, &$edit, &$account, $category = NULL) {
if ($type == 'view') {
$account->content['user_picture'] = array(
'#value' => theme('user_picture', $account),
'#weight' => -10,
);
if (!isset($account->content['summary'])) {
$account->content['summary'] = array();
}
$account->content['summary'] += array(
'#type' => 'user_profile_category',
'#attributes' => array('class' => 'user-member'),
'#weight' => 5,
'#title' => t('History'),
);
$account->content['summary']['member_for'] = array(
'#type' => 'user_profile_item',
'#title' => t('Member for'),
'#value' => format_interval(time() - $account->created),
);
}
if ($type == 'form' && $category == 'account') {
$form_state = array();
return user_edit_form($form_state, (isset($account->uid) ? $account->uid : FALSE), $edit);
}
//<-- LOOK HERE -->
if ($type == 'validate' && $category == 'account') {
return _user_edit_validate((isset($account->uid) ? $account->uid : FALSE), $edit);
}
if ($type == 'submit' && $category == 'account') {
return _user_edit_submit((isset($account->uid) ? $account->uid : FALSE), $edit);
}
if ($type == 'categories') {
return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
}
}
So, it is only supposed to validate if the category == 'account'
In the function _use_edit_validate, we find:
// Validate the e-mail address:
if ($error = user_validate_mail($edit['mail'])) {
form_set_error('mail', $error);
}
There's your error message.
Since that form is only supposed to validate when the category == 'account', and your problem (#2) seems to be that it always validates regardless of the category, maybe your forms are not being rendered as unique form instances? Drupal might be rendering a complete form each time, and just setting a hidden form value to whatever the category is (like in this form's definition function in user_pages.inc $form['_category'] = array('#type' => 'value', '#value' => $category);)
It would be helpful to see the actual html source output.
==EDIT 10-15-09 in response to updated question===
OK, it looks like your method (editing $form['#action'] manually in the theme layer) may not be possible (see this post for reference). If you want to alter the form action you need to write a custom module that implements hook_form_alter() (it won't work in a theme template file). This function allows you to modify how a form is rendered, in your case the user modification form. There are more details on form modification here.
I am not 100% sure that's what you want to do though; (since it looks like you already must create a module) perhaps you want to hook into hook_user() instead; this function "... allows modules to react when operations are performed on user accounts.". You may be able to react to the category in this function and block/allow whichever user changes you like.
However, if it's just email address validation that is the problem, and if you are dealing with existing users, why don't you just make sure the email address is set before you save?