silverstripe custom form field error message - silverstripe

In my form processing function I have:
$form->addErrorMessage('Email', 'Your email address is already registered in our system','bad');
and in my template:
$Fields.FieldByName(Email)
I can see that the bad class has been added to the input, but how do I display an inline error message?

I'm not sure if this is what you are looking for, but I do something like this:
public function MyFormAction(){
//do something
if(//something is wrong){
$this->MyErrorMessage = 'Something is wrong';
return $this->renderWith(array('MyFormPage', 'Page'));
}
}
And then in the template I can put where I want:
<% if $MyErrorMessage %>
<p class='bad'>$MyErrorMessage</p>
<% end_if %>

You have to only add bellow in your $form->addErrorMessage('Email', 'Your email address is already registered in our system','bad');
return $this->redirectBack();
I'm using this on all my forms. Be sure to use this inside a Submit function. You will be redirected to your form with the error message below the field Email. You dont need to create a custom template for this.

Related

How to pass WooCommerce order object to custom JS on clicking order button

I'm building a WooCommerce custom payment gateway and want to run some JS when the user clicks the order button, but I need that JS to have access to the order object. So far, what I have is something like this:
public function __construct() {
// constructor stuff, yadda yadda yadda
add_action( 'woocommerce_after_checkout_form', array( $this, 'checkout_click_handler' ) );
}
public function checkout_click_handler() {
?>
<script type="text/javascript">
jQuery(document).on( "updated_checkout", function(){
// do JS stuff here, but no access to order object
});
</script>
<?php
}
Ideally, I'd like to be able to pass the $order object into that action callback, then I could stringify it as JSON to pass it to the JS.
UPDATE: Ok, I realized I am thinking about this the wrong way, although a similar problem still exists. That function checkout_click_handler() is added to the HTML long before the user fills out their information and clicks the order button. What I really need is for the process_payment() function to be able to somehow inject new HTML once it receives the order details. Is that possible?

Contact form 7 required one of 2 different fields

I have a image upload field and a URL field in CF7 and how can i make it that a user needs to use one of the 2 fields. So select a image or put a link in the URL field?
I already search a little and i saw some options to do it on normal txt fields but that was not working for me i think because of the upload field.
I don't think that CF7 can do this out of the box. You would probably have to go down to code to solve this issue.
Since I don't know how big you form is this could maybe help you out:
https://wordpress.org/plugins/cf7-conditional-fields/ - Plugin for conditional field inside CF 7
https://conditional-fields-cf7.bdwm.be/conditional-fields-for-contact-form-7-tutorial/ - Tutorial how to use it.
So with this plugin you could basically create a dropdown in which the user first has to select if he wants to use an image or use the URL field. After that, only his selection would pop up and he can proceed with the selected option.
If you want to do the coding you can add some JS to the site and check on validation if one of the two fields is filled out or not.
If the plugin solves your issue - great, if not let me know so I can help you out with the code validation.
###Edit since we need code###
So to dynamically alter the required function I found a pretty good post:
Dynamically Disable Contact Form 7 Field Validation
Some Background information:
CF7 does the validation on server side, so working with JS or JQuery won't help in this case. What we are going to do is manipulate the server validation. If one of the fields is filled out correctly we are just putting content in the other field on the validation.
I created a form that looks like this:
The form in CF7 module looks like this:
<label> URL
[url* url ]
<label> Image
[file* image ]
[submit "Send"]
Then you just have to add the following code to your functions.php file of your theme.
function alter_wpcf7_posted_data( $data ) {
if($_FILES['image']['size'] != 0) {
$_POST['url'] = "http://fileupload.com";
}
if($_POST['url'] != "") {
$_FILES['image']['tmp_name'] = "urlprovided";
}
return $data;
}
add_filter("wpcf7_posted_data", "alter_wpcf7_posted_data");
Normally both fields will be empty in the beginning, if one of them has contet the other one gets fake data and the use has only to provide one.
Let me know if this helps.
I think i found the solution with a little help of the code from #Aschi33.
I made the image (upload field) required and the url field not. So there needs to be alwasy a image selected. But with this code:
function alter_wpcf7_posted_data( $data ) {
if($_POST['url'] != "") {
$_FILES['image']['tmp_name'] = "urlprovided";
}
return $data;
}
add_filter("wpcf7_posted_data", "alter_wpcf7_posted_data");
if the URL field is filled in then the required image field is faked to be filled in so then the URL field can be used to submit the form.
And then with this code:
function cf7_custom_url_check( $result, $url ) {
if ($result) {
$regex='/^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/';
if (!preg_match($regex,$url)) $result=FALSE;
}
return $result;
}
add_filter( 'wpcf7_is_url', 'cf7_custom_url_check', 10, 2 );
I check if its a real video link from YouTube and if not the field will give a error.

add_filter not working on Wordpress custom login page

I'm creating a custom login page in wordpress. Everything is good so far but I want to add error handling to my page.
In default-filters.php, I added this:
add_filter('authenticate', 'wp_return_login_error', 40, 3);
In users.php, I added this:
function wp_return_login_error(){
if (is_wp_error($user)) {
$error = $user->get_error_message();
wp_redirect( get_permalink() . "/login/?login=failed&reason=" . $error);
exit;
}
}
No matter what, when you enter invalid/blank credentials, the user is simply redirected to the login screen without any indication of what went wrong. I tried adding debug messages in my function and it looks like it isn't being called.
What should I try?
Thanks in advance for your help.
The easiest way around this is to change the error message with this code in your functions.php file:
function login_error_override()
{
return 'Incorrect login details.';
}
add_filter('login_errors', 'login_error_override');

Silverstripe Multiple Userforms on one page

I am trying to create a single page that will display multiple userforms in a tabbed view. For example basic contact form, request a quote form etc.
I thought I could make a new page type and loop through the children to display the forms, but the $Form variable isn't rendering the form.
<% loop $Children %>
<div>
<h2>$Title</h2>
$Form
</div>
<% end_loop %>
Am I missing something here, or is there a different way to render a form using a its ID in a template file?
You could try the following.
Create a function in your page holder controller to get the form from a specific child (must be a UserDefinedForm page). To do this you'll need to create the controller of this child page.
public function ChildForm($pageID) {
$page = UserDefinedForm::get()->byID($pageID);
$controller = UserDefinedForm_Controller::create($page);
return $controller->Form();
}
afterwards you'll call this function in your loop and pass the current child id to it
<% loop $Children %>
<div>
<h2>$Title</h2>
$Top.ChildForm($ID)
</div>
<% end_loop %>
This should (code is untested) return the forms you want.
The problem at play here is the difference between the DataObject/Page and the Controller. Looping over $Children returns you a DataObject whereas the Form function and template variable are part of UserDefinedForm's controller.
The other answer shows one working solution however it has some hair on it:
Jumping scope to your controller to pass an ID to get your form
Additional DB query
Requires all the child pages to be of type UserDefinedForm
We can implement a more generic solution that removes some of those elements and making your code a little more maintainable.
Take the following which would be added to the Page class (not the controller):
function getInLoopForm() {
if (in_array('UserDefinedForm', $this->ClassAncestry)) {
$controllerName = $this->ClassName . '_Controller';
$controller = $controllerName::create($this);
if ($controller->hasMethod('Form')) {
return $controller->Form();
}
}
return false;
}
The first part of that checks whether the current object has UserDefinedForm in its class ancestry. If it is, we then create the appropriate controller and return the form.
Your template code would look like this instead:
<% loop $Children %>
<div>
<h2>$Title</h2>
$InLoopForm
</div>
<% end_loop %>
This solution is generic for three reasons:
In our getInLoopForm function, the value "UserDefinedForm" can be replaced with any class that extends Page. It could even be brought out to a YML value if you were so inclined.
For SilverStripe, controller names for pages must match "{PageClassName}_Controller" so we can abuse that by working out the controller name dynamically. This allows for you to extend UserDefinedForm and its controller and we can still call the right function.
You only require your DataObject to access the form, you don't need your own controller.
For SS 4 there is a small code change needed:
public function getInLoopForm() {
if (in_array('SilverStripe\UserForms\Model\UserDefinedForm', $this->ClassAncestry)) {
$controller = UserDefinedFormController::create($this);
if ($controller->hasMethod('Form')) {
return $controller->Form();
}
}
return false;
}

How can I redirect a Drupal user after they create new content

I want to redirect my users after they create a piece of new content, instead of directing them to the 'view' page for the content.
I have seen mention of using hook_alter or something, but I'm really new to drupal and not even sure what that means?
Thanks!
As you mention that you are new to Drupal, I'd suggest to take a look at the Rules module. You can add a trigger on for content has been saved/updated and add an action, to redirect the user to a specific page.
You can however do the same in a light weight custom module using a form_alter hook.
First, find the form ID of the form. For node forms, it's the [node-type]_node_form.
Then, you can add a new submit function to be executed when the form is submitted. In this submit handler, set the redirect path.
See this guide on a basic how-to on creating a module.
Your module code would be something like belows:
<?php
function mymodule_mytype_node_form_alter(&$form, &$form_state) {
$form['#submit'][] = 'mymodule_node_submit_do_redirect';
}
function mymodule_node_submit_do_redirect($form, &$form_state) {
$form_state['redirect'] = 'my_custom_destination';
}
A much much simpler approach is to set the destination in the node form's URL.
For example, if you opened http://example.com/node/add/mytype?destination=my_custom_destination, you will be redirected to that URL instead of the node view page.
This works for me using Drupal 7, after creating a new module!
Put into the .module file the following PHP code:
<?php
function custom_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == '[node-type]_node_form') {
$form['actions']['submit']['#submit'][]= 'my_custom_submit_handler';
}
}
function my_custom_submit_handler($form, &$form_state) {
$form_state['redirect'] = 'http://www.expamle.eu/?q=node/2';
}
You just need to change [node-type]_node_form with your node type name (e.g.: example_node_form) and the http://www.expamle.eu/?q=node/2 with the correct URL.

Resources