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

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;
}
?>

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 );

Gravity Form Shortcode Confirmation

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 );

Conditional Validation in ZF2

I have a form which starts with a Select with two options. There are several other fields, some of which are required for the first Select option, and the others required for the second Select option.
In the view, I'm using the Select to show/hide the relevant/irrelevant fields. Most of these fields are required when their option in the Select is selected.
What is the best way to only validate the fields that are relevant to whatever is selected in the Select?
In your controller, you could do something like that (the key is the form's setValidationGroup function):
//GET THE FORM
$form = $this->getServiceLocator()->get( '<FORM_NAME>' );
//GET THE POSTED DATA
$request = $this->getRequest();
$data = get_object_vars( $request->getPost() );
//DEPENDING ON THE SELECT VALUE, VALIDATE THIS OR THAT FIELDS
if ( $data[ 'SELECT_NAME' ] === 'A' ) {
$form->setValidationGroup( array( 'INPUT_A', 'INPUT_B' ) );
} else {
$form->setValidationGroup( array( 'INPUT_C', 'INPUT_D' ) );
}
//PERFORM THE FORM VALIDATION
if ( !$form->isValid() ) {
//FORM IS WRONG
( ... )
}
//FORM IS OK
( ... )

Zend_Form not displaying error message with calling addError

I am implementing an updatePasswordAction and its not displaying an error with an invalid current password. I could not implement this with a Zend_Validate class to use with a supplied record->password, so i just validated for now in my controller action and if failed then i add the error message to the form element. this is just before i run $form->isValid. In any case, its working. but when the validation fails, its not displaying the error message on this on the element. any help would be greatly appreciated.
FYI: When I submit a blank current password, it shows the validation
class Admin_Form_UserPassword extends Katana_Form
{
public function init()
{
$element = $this->createElement('hidden', 'id');
$this->addElement($element);
$element = $this->createElement('password','password');
$element->setLabel('Current Password:');
$element->setRequired(true);
$this->addElement($element);
$element = $this->createElement('password','new_password');
$element->setLabel('New Password:');
$element->addValidator('StringLength', false, array(6,24));
$element->setRequired(true);
$element->addValidator('NotEmpty');
$this->addElement($element);
$element = $this->createElement('password','new_password_confirm');
$element->setLabel('Confirm:');
$element->addValidator('StringLength', false, array(6,24));
$element->addValidator('IdenticalField', false, array('new_password', 'Confirm Password'));
$element->setRequired(true);
$this->addElement($element);
$this->addElement('submit', 'submit', array('label' => 'Submit'));
}
}
public function updatePasswordAction()
{
$resourceModel = new Core_Model_Resource_User();
$form = new Admin_Form_UserPassword();
$form->setMethod(Katana_Form::METHOD_POST);
$form->setAction($this->getActionUrl('update-password'));
if($this->getRequest()->isPost()){
$id = $this->getRequest()->getParam('id');
$record = $resourceModel->find($id)->current();
$currPassword = $record->password;
$typedPassword = md5($this->getRequest()->getParam('password'));
if($currPassword !== $typedPassword){
$form->getElement('password')->addError('Current password is incorrect.');
}
if($form->isValid($_POST)){
$data = $form->getValues();
$result = $resourceModel->updatePassword($id, $data['new_password']);
if($result){
$this->redirectSimple('list');
}
}
} else {
$id = $this->getRequest()->getParam('id');
$recordData = array(
'id' => $id
);
$form->populate($recordData);
}
$this->getView()->form = $form;
}
Adding an error to the element doesn't cause the form itself to then be invalid.
There are at least 2 methods I use to get around this:
if($currPassword !== $typedPassword){
$form->getElement('password')->addError('Current password is incorrect.');
$form->markAsError();
}
// or
if ($form->isValid($_POST) && 0 == sizeof($form->getMessages()) {
// form was valid, and no errors were set on elements
}
To clarify, when you add the error to the form ELEMENT, there is an error attached to that element, but Zend_Form::isValid only runs the validators and sets appropriate errors, it doesn't check to see if you had set an error on a particular element.
You can however call $form->getMessages() to get all the error messages attached to the form or its child elements. If this is 0 and you have validated your form, then it means there were no errors. If your form passed isValid but you added an error to an element, it will include the error message you added.
I made it work this way.
Controller:
if ($trial->getKind() != 'debt' && $_POST['kind'] == 'debt')
{
$editForm->getElement('kind')->markAsError();
}
if ($editForm->isValid($_POST)) { ... }
Form:
public function isValid($data)
{
$valid = parent::isValid($data);
if ($this->getElement('kind')->hasErrors()) {
$this->getElement('kind')->addError($this->_translate->translate('You can\'t change trial kind to debt.'));
$valid = false;
}
return $valid;
}
And this comment helped me.

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?