Jump to content
pwFoo

FrontendUser: login, logout and register users / members

Recommended Posts

Thanks for the guidance. I don't like captcha's either, but for this site, admins need to approve every registration by hand, so no validation emails can be sent. Akismet or http://stopforumspam.com/ might be alternatives.

The recaptcha module does not require any additional form fields.

So would the hooking thing be something like:

        $form->addHookAfter('processInput', function() {
    
        $recaptcha = wire('modules')->get('Recaptcha')->verifyResponse(wire('input')->post->g-recaptcha-response);
        if(!$recaptcha) {
             $form->fhSubmitBtn->error('reCAPTCHA validation not ok!');
        }
        });

It seems I don't understand where to put it, though. If it is in my register.php, I get a Fatal error: Call to a member function addHookAfter() on null.

Should I put it somewhere in FrontendUser.module (Build registration form function?) or FormHelper.module (Extended PW form api processing function?)?

I'm in no particular hurry to find out, so please focus on your own pressing matters first :)

Share this post


Link to post
Share on other sites

No need to change FormHelper or FrontendUser modules.

Have you set $form inside your template like that?

$form = $fu->form;

Try something like that inside your template file (untested code!).

// load module
$fu = $modules->get('FrontendUser');

// prepare / create register form with default fields
$fu->register();

// Add hooks to the form / fields
// Your code here 
$fu->form->addHookAfter('processInput', function() {
        $recaptcha = wire('modules')->get('Recaptcha')->verifyResponse(wire('input')->post->g-recaptcha-response);
        if(!$recaptcha) {
             $form->fhSubmitBtn->error('reCAPTCHA validation not ok!');
        }
});

// process register / form submit
$fu->process($redirectDestination);

// output register form
echo $fu->render();

Share this post


Link to post
Share on other sites

Ok, I was being a bit slow again.. I didn't even render the recaptcha! :-[

So I added to the top

$recaptcha = $modules->get('Recaptcha');

(also $form = $fu->form ;)

and

echo $recaptcha->render();

below the fu render.

Here is the rendering code from the module:

$html = '<script src="'.$this->getJsLink($lang).'" async defer></script>'."\n";
$html .= '<div class="g-recaptcha"'.$this->buildAttributes($attributes).'></div>';

Then this response element is created through JS:

<textarea id="g-recaptcha-response" name="g-recaptcha-response" class="g-recaptcha-response" style="width: 250px; height: 40px; border: 1px solid #c1c1c1; margin: 10px 25px; padding: 0px; resize: none;  display: none; "></textarea>

Yet, the recaptcha answer (=I'm not a robot) seems to somehow not be processed as I get

Fatal error: Call to a member function error() on null

I guess I'll bother the author of the recaptcha module next..

As a new tangent, I'm giving you this proposition to make the module become aware of EmailNewUser.

Edit: well, it is enough to call in my register.php: $modules->get('EmailAdminNewUser');

Share this post


Link to post
Share on other sites

The recaptcha module author answered and I noticed I had wrong syntax for the verifyResponse bit (copied from Nico's post).

I also now use wire('') for everything inside the function..

Now there are no other notices than

Fatal error: Call to a member function error() on null

After submitting my registration.

Referring to the fhSubmitBtn->error

Here is my complete register.php:

<?php
if(!$user->isLoggedin()) {
  // load module
  $fu = $modules->get('FrontendUser');
  $recaptcha = $modules->get('Recaptcha');
  // prepare register form
  $fu->register();
 
  $form = $fu->form;

  // process register / form submit
  $redirectDestination = $pages->get(1)->url;
 
        $form->addHookAfter('processInput', function() {

        $recaptchaverify = wire('modules')->get('Recaptcha')->verifyResponse(wire('input')->post('g-recaptcha-response'));
        if(!$recaptchaverify) {
             wire('modules')->get('FrontendUser')->fhSubmitBtn->error('reCAPTCHA validation not ok!');
        }
        });
  $fu->process($redirectDestination);

?>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title><?php echo $title; ?></title>
        <link rel="stylesheet" type="text/css" href="<?php echo $templatesurl; ?>css/mystyle.css" />
    <link rel="stylesheet" type="text/css" href="<?php echo $templatesurl; ?>css/somestyle.css" />    
    </head>
    <body>
    <div class="container">
    <p>Ylläpito vahvistaa kaikki rekisteröitymiset. Saat sähköpostia, kun olet saanut käyttöoikeudet.</p>
<?php  // output register form
  echo $fu->render();
  echo $recaptcha->render();
?>
    </div>
    </body>
</html>
<?php  die();
}

Share this post


Link to post
Share on other sites

You loaded recacptcha module :

$recaptcha = $modules->get('Recaptcha');

No need to reload module :

$recaptchaverify = wire('modules')->get('Recaptcha')->verifyResponse(wire('input')->post('g-recaptcha-response'));

You can use it like : 

$recaptchaverify = $recaptcha->verifyResponse(wire('input')->post('g-recaptcha-response'));

and same for frontenduser module

is there a funtion $fu->fhSubmitBtn->error() ? I didn't use and check module codes or usages be sure there is a function exist... Error mean there is no function exist !

Share this post


Link to post
Share on other sites

No, I can't use them like that inside the function.

If I do, I get an error like this on submit:

Notice: Undefined variable: recaptcha in C:\BitNami\wampstack-5.6.2-0\apache2\htdocs\mysite\site\templates\register.php on line 22

Fatal error: Call to a member function verifyResponse() on null in C:\BitNami\wampstack-5.6.2-0\apache2\htdocs\mysite\site\templates\register.php on line 22

Is there something I'm missing?

Share this post


Link to post
Share on other sites

I see hook function now, its ok but be sure there is wire('modules')->get('FrontendUser')->fhSubmitBtn->error(); function exist.

Share this post


Link to post
Share on other sites

Can you try it like :

wire('modules')->get('FrontendUser')->form->fhSubmitBtn->error('reCAPTCHA validation not ok!');

And also you can use loaded modules or variables like this :
 

$form->addHookAfter('processInput', function() use($fu, $recaptcha, $input) {
        $recaptchaverify = $recaptcha->verifyResponse($input->post('g-recaptcha-response'));
        if(!$recaptchaverify) {
             $fu->form->fhSubmitBtn->error('reCAPTCHA validation not ok!');
        }
});
  • Like 1

Share this post


Link to post
Share on other sites

Thanks heaps! Now there are no errors.

Now I'm just left wondering, why recaptcha validation is not ok :)

I was testing on localhost and it should work with the API keys, but I'll try in the online website next.

Edit: didn't work in the online website either..

Share this post


Link to post
Share on other sites

Thanks heaps! Now there are no errors.

Now I'm just left wondering, why recaptcha validation is not ok :)

I was testing on localhost and it should work with the API keys, but I'll try in the online website next.

Edit: didn't work in the online website either..

You can test recacptcha also on localhost ! But be sure you are using virtual host or when you create a key be sure there is your local domain also added.

Share this post


Link to post
Share on other sites

@ukyo: thanks for your tip in PM! Now I could successfully create the user, passing the recaptcha validation!! O0

Adding a post checking condition did the trick:

$form->addHookAfter('processInput', function() use($fu, $recaptcha, $input) {
        if(isset(wire('input')->post) && wire('input')->post('fuRegisterForm') == 'fuRegisterForm') {
          $recaptchaverify = $recaptcha->verifyResponse($input->post('g-recaptcha-response'));
          if(!$recaptchaverify) {
               $fu->form->fhSubmitBtn->error('reCAPTCHA validation not ok!');
          }
        }
        });

Share this post


Link to post
Share on other sites

fhSubmitBtn is part of FormHelper and not FrontendUser. That's why you have to use

$fu->form->fhSubmitBtn to get the object and der the Form field error ;)

Inside a hook you can use

$fu = wire('fu');

to work with the FrontendUser object / instance.

Or also the FU Form:

$form = wire('fu')->form

Share this post


Link to post
Share on other sites

I'm trying to add an extra field for my registration form: fullname.

Still calling the registration with $fu->register();

I've changed the FrontendUser.module:

// create registration form
        if (empty($fields)) {
            $fields = array('username', 'email', 'password', 'fullname');
        }

and added this:

/**
     * Fullname form field
     * @return InputfieldText Fullname field
     */
    protected function fullnameRegister() {
        $field = $this->modules->get('InputfieldText');
        $field->label = $this->_('Koko nimesi');
        $field->attr('id+name', 'fullname');
        $field->required = 1;
        $field->fhSanitizer = 'text';
        $field->addHookAfter('processInput', function($event) {
            $field = $event->object;
            $fullname = wire('fu')->form->fhValue($field->fullname);
            
            if (empty($fullname))   return;
            else {
              wire('fu')->userObj->fullname = $fullname;
            }
        });
        return $field;

The form field is added fine, but the input is not saved to the user's fullname field. Is there something I'm missing?

Share this post


Link to post
Share on other sites

First... do NOT modify the module! Extend it!

Just define the field and add it to the register() optional field array.

Read the wiki documentation (https://bitbucket.org/pwFoo/frontenduser/wiki/Documentation#markdown-header-register). Also take a look at code comments).

Have you added the field "fullname" to the user template? If field is added and value is der ro the userObj it should be saved. See nickname example (https://bitbucket.org/pwFoo/frontenduser/wiki/Register%20extensions%20and%20plugins) and add debugging output to check your value.

Share this post


Link to post
Share on other sites

I read the documentation & examples carefully before deciding I have to modify the module. Besides, I wanted to modify the module in any case, because I wanted to translate the labels etc. to Finnish..

I do have the fullname field in the user template, which is the reason I would like the users to be able to populate it already on registering.

This is the best I could do to debug:

I changed the function process:

if ($result === true) {
                var_dump($this->userObj);
                //$this->session->redirect($redirect, false);     // User sucessfully registered
            }

Then I could see that the fullname is empty:

["data"]=> array(10) { ["email"]=> string(16) "dkjdfaa@dfds.com" ["pass"]=> object(Password)#305 (0) { } ["fullname"]=> string(0) "" ["roles"]=> object(PageArray)#306 (6)

The fieldtype for fullname is text, matching what is in fullnameRegister..

How can I debug further to see where it fails to save the input?

Share this post


Link to post
Share on other sites

You can translate the field labels or modify the fields (set your own label). Nö need to hack the module ;)

Is $field->fullname the field name string?

$fullname = wire('fu')->form->fhValue($field->fullname);

Should be something like that.

$fullname = wire('fu')->form->fhValue("fullname");

Just add a debugging output inside your hook to verify that.

FormHelper documentation

https://bitbucket.org/pwFoo/formhelper/wiki/Documentation

No PC here to take a closer look. Mobile only for two weeks ;)

Share this post


Link to post
Share on other sites

Ah, I had never tried that module translation method.. Languages - Select file does work fine.

$fullname = wire('fu')->form->fhValue("fullname");

YES! That solved it!

But why did it not accept $field->fullname, when it is added to the fields array with

$fields = array('username', 'email', 'password', 'fullname');

I tried both

$fu->register();

and

$fu->register(array('username', 'email', 'password', 'fullname'));

It made no difference.

So how could I do this without hacking the .module file?

I have to somehow add the function fullnameRegister or recreate its functionality and execution.

I have no idea how to do this and it will probably take me 1-2 hours to figure it out (which is why I went with the straight hacking method initially).

Edit: the easiest way would be to simply:

$fu->fullnameRegister = function() {

and add my function there, in my register.php. But the class is not built to accept adding new functions to itself.

Then if I try to add a hook to buildForm, I get "Method FrontendUser::buildForm is not hookable"

Edit2: damn, I managed to spend 1-2 hours today on this, plus maybe 3-4 hours yesterday and only now do I realize pwFoo already supplied the answer in May!

Share this post


Link to post
Share on other sites

Hi Beluga,

so all problems solved now? :)

The module is designed to be as flexible as possible. All addons and also changes should be done with params (add or replace fields) and hooks (additional or changes processing). You can translate labels and also change fields from outside if needed...

$usernameField = $fu->form->get("username");

$usernameField->label = "New label";

All is based on PW hooks and PW form api / PW fields.

Share this post


Link to post
Share on other sites

Yes, all problems solved except depression and embarrassment after failing to notice the existing code snippet.

I think it should be added to the documentation examples as it's such a common use-case.

Share this post


Link to post
Share on other sites

Hi pwFoo, thanks VERY much for this great module :)

Please could you let me know if there is an easy way to prepopulate the username with a value I have in a variable?

I see I can use the code

$fu->register(array('username', 'email', 'password'));

but I can't work out how modify it to not offer the visitor a Username field but for it instead to be prepopulated so at time of submission the username field gets the prepoulated value.

Thanks for any pointers and sorry if this is obvious and I've missed it in my searches. Cheers, -Alan

Share this post


Link to post
Share on other sites

Conditional hide / remove fields from form, advanced processing is done in the RegisterEmailValidation plugin.

Password field was removed before the form will be rendered.

https://bitbucket.org/pwFoo/frontenduser/src/71207f581585ac6e089b47790eadbf3bdbedd5a9/FrontendUser/FrontendUserRegisterEmailValidation.module?at=master#FrontendUserRegisterEmailValidation.module-155

But it's a required field, so required have to be changed to false before form process.

https://bitbucket.org/pwFoo/frontenduser/src/71207f581585ac6e089b47790eadbf3bdbedd5a9/FrontendUser/FrontendUserRegisterEmailValidation.module?at=master#FrontendUserRegisterEmailValidation.module-65

It should be also possible to skip the username field.

$fu->register(array('email', 'password'));

It isn't required by the module, but the you have to set the needed attributes before you call ___save($user)

$user is a PW User object.

So a pre-save hook (like used with additional nickname plugin) should work for you.

$fu->addHookBefore('save', function($event) {
    $form = wire('fu')->form;

    if(!count($form->getErrors())) {
        wire('fu')->userObj->nickname = $form->fhValue('username', 'text');
    }
});

Just change it to wire('fu')->userObj->username = ...

  • Like 2

Share this post


Link to post
Share on other sites

Thanks pwFoo, I'd tried with a pre-save hook but had used the wrong construction, I'll try your version—thanks for the fast reply ^_^

Share this post


Link to post
Share on other sites

Sanitize field value is a FormHelper feature ;)

Set sanitizer to field as an additional attribute

$emailField->fhSanitizer = 'email';

Get sanitized value after form processing / submitted

$value = $fu->form->fhValue('emailField')

Change sanitizer if needed...

$value = $fu->form->fhValue('emailField', 'pageName')

Or just do it without FormHelper inside a field processInput hook

// hook after field processed (form need to be submitted)
$myField->addHookAfter('processInput', function($event) {
  $currentField = $event->object;
  
  $value = $currentField->value;
  §sanitizedValue = wire('sanitizer')->pageName($value);

  // Do ...
}

You can take a look in each FU field (like username field for registration) to see some examples. ;)

Or at the wiki plugin examples (register, login).

Set additional user field "nickname" based on username during registration (plugin).

Just hook before "save", generate the value and set it to the userObj. "userObj" is a temp object of type User. All existing fields will be saved.

$fu->addHookBefore('save', function($event) {
    $form = wire('fu')->form;

    if(!count($form->getErrors())) {
        wire('fu')->userObj->nickname = $form->fhValue('username', 'text');
    }
});

You need an additional field with user input? Add a field with sanitizer and a processing hook... Same as username field ;) So you can use it as starting point

        $myField = $modules->get('InputfieldText');
        $myField->label = $this->_('MyLabel');
        $myField->attr('id+name', 'MyField');
        //$myField->required = 1;
        $myField->fhSanitizer = 'text';
        // Call hook after field is processed by PW form api
        $myField->addHookAfter('processInput', function($event) {
            $field = $event->object;

            // Value will be sanitized as text with "$sanitizer->text()"
            $mySanitizedCustomInput = wire('fu')->form->fhValue($field->name);
            
            // Do ...
           
            // Example: Add value to user during registration
            wire('fu')->userObj->myField = $mySanitizedCustomInput;

            // Need to set an field error?
            // $field->error('Custom field has an error...');
        });

        // Define the field before you call FU and add it as additional field...
        $fu->register(array('username', 'email', 'password', $myField));

If You need more examples or have a plugin idea just post it here.

Hello, 

i have the new fileds, I dont really understand how to write the form values to the user template values ? 

Cound you post an example ? 

Also I need that an email will sent to the admin if an user is registered. User have to be activated and chooses for a group by the admin. 

Thanx for the advice 

Share this post


Link to post
Share on other sites

Hello, 

i have the new fileds, I dont really understand how to write the form values to the user template values ? 

Cound you post an example ? 

Also I need that an email will sent to the admin if an user is registered. User have to be activated and chooses for a group by the admin. 

Thanx for the advice 

For email notification and admin activation see this conversation.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By BitPoet
      Here's a small new module that started as a spinoff of a memcache proof-of-concept. Cache your strings and partials in-memory using Redis as a backend.
      CacheRedis
      All you need is a running Redis database. The module supports connection through regular TCP, over TLS and via unix domain sockets. Host and port are configurable, and authentication is supported too. Here's a screenshot of the module configuration options:

      I'll not go into too many details about the usage, you can see everything explained in the README on GitHub, and just highlight the most important points.
      When the module is active, you'll have a wired $redis variable, which means you can reach the module as $redis, wire("redis") or within Wire classes / modules as $this->redis.
      CacheRedis is strongly influenced by WireCache, and its usage is (hopefully) straight forward.
      // Store an entry in the cache under the given key name with the given value: $redis->store("cached_value_number_one", $expire, $value); // Retrieve a value from the cache $value = $redis->fetch($key); // Delete a cache entry $redis->delete("my_other_cached_value"); // Clear the whole cache $redis->flush(); // Retrieve a value from the cache, and if not found, create it through the given function // and store it with a lifetime of 5 minutes (300 seconds) $value = $redis->fetch($key, 300, function() use($page) { return "Page last changed on " . strftime('%m/%d/%Y %H:%M', $page->modified | $page->created); }); // Render a file using wireRenderFile and store it in the cache. // We'll pass a selector as the expiry value so this cache gets // emptied every time a page matching the selector is saved. $news = $redis->renderFile("partials/news.php", 'template=blog-post', ["page" => $page]); The module is still very crude work in progress, but I hope some of you feel daring, try it out and let me know in case anything breaks.
      Have fun!
    • By joshua
      This module is (yet another) way for implementing a cookie management solution.
      Of course there are several other possibilities:
      - https://processwire.com/talk/topic/22920-klaro-cookie-consent-manager/
      - https://github.com/webmanufaktur/CookieManagementBanner
      - https://github.com/johannesdachsel/cookiemonster
      - https://www.oiljs.org/
      - ... and so on ...
      In this module you can configure which kind of cookie categories you want to manage:

      You can also enable the support for respecting the Do-Not-Track (DNT) header to don't annoy users, who already decided for all their browsing experience.
      Currently there are four possible cookie groups:
      - Necessary (always enabled)
      - Statistics
      - Marketing
      - External Media
      All groups can be renamed, so feel free to use other cookie group names. I just haven't found a way to implement a "repeater like" field as configurable module field ...
      When you want to load specific scripts ( like Google Analytics, Google Maps, ...) only after the user's content to this specific category of cookies, just use the following script syntax:
      <script type="optin" data-type="text/javascript" data-category="statistics" data-src="/path/to/your/statistic/script.js"></script> <script type="optin" data-type="text/javascript" data-category="marketing" data-src="/path/to/your/mareketing/script.js"></script> <script type="optin" data-type="text/javascript" data-category="external_media" data-src="/path/to/your/external-media/script.js"></script> <script type="optin" data-type="text/javascript" data-category="marketing">console.log("Inline scripts are also working!");</script> The type has to be "optin" to get recognized by PrivacyWire, the data-attributes are giving hints, how the script shall be loaded, if the data-category is within the cookie consents of the user. These scripts are loaded asynchronously after the user made the decision.
      If you want to give the users the possibility to change their consent, you can use the following Textformatter:
      [[privacywire-choose-cookies]] It's planned to add also other Textformatters to opt-out of specific cookie groups or delete the whole consent cookie.
      You can also add a custom link to output the banner again with a link / button with following class:
      <a href="#" class="privacywire-show-options">Show Cookie Options</a> <button class="privacywire-show-options">Show Cookie Options</button> This module is still in development, but we already use it on several production websites.
      You find it here: PrivacyWire Git Repo
      Download as .zip
      I would love to hear your feedback 🙂
      CHANGELOG
      0.0.5 Multi-language support included completely (also in TextFormatter). Added possibility to async load other assets (e.g. <img type="optin" data-category="marketing" data-src="https://via.placeholder.com/300x300">) 0.0.4 Added possibility to add an imprint link to the banner 0.0.3 Multi-language support for module config (still in development) 0.0.2 First release 0.0.1 Early development
    • By MoritzLost
      This is a new module that provides a simple solution to clearing all your cache layers at once, and an extensible interface to perform various cache-related actions.
      The simple motivation behind this module was that I was tired of manually clearing caches in several places after deploying a change on a live site. The basic purpose of this module is a simple Clear all caches link in the Setup menu which clears out all caches, no matter where they hide. You can customize what exactly the module does through it's configuration menu:
      Expire or delete all cache entries in the database, or selectively clear caches by namespace ($cache API) Clear the the template render cache. Clear out specific folders inside your site's cache directory (/site/assets/cache) Refresh version strings for static assets to bust client-side browser caches (this requires some setup, see the full documentation for details). This is the basic function of the module. However, you can also add different cache management action through the API and execute them through the module's interface. For this advanced usage, the module provides:
      An interface to see all available cache actions and execute them. A system log and logging output on the module page to see verify what the module is doing. A CacheControlTools class with utility functions to clear out different caches. An API to add cache actions, execute them programmatically and even modify the default action. Permission management, allowing you granular control over which user roles can execute which actions. The complete documentation can be found in the module's README.
      Beta release
      Note that I consider this a Beta release. Since the module is relatively aggressive in deleting some caches, I would advise you to install in on a test environment before using it on a live site.
      Let me know if you're getting any errors, have trouble using the module or if you have suggestions for improvement!
      In particular, can someone let me know if this module causes any problems with the ProCache module? I don't own or use it, so I can't check. As far as I can tell, ProCache uses a folder inside the cache directory to cache static pages, so my module should be able to clear the ProCache site cache as well, I'd appreciate it if someone can test that for me.
      Future plans
      If there is some interest in this, I plan to expand this to a more general cache management solution. I particular, I would like to add additional cache actions. Some ideas that came to mind:
      Warming up the template render cache for publicly accessible pages. Removing all active user sessions. Let me know if you have more suggestions!
      Links
      https://github.com/MoritzLost/ProcessCacheControl ProcessCacheControl in the Module directory

    • By David Karich
      Admin Page Tree Multiple Sorting
      ClassName: ProcessPageListMultipleSorting
      Extend the ordinary sort of children of a template in the admin page tree with multiple properties. For each template, you can define your own rule. Write each template (template-name) in a row, followed by a colon and then the additional field names for sorting.
      Example: All children of the template "blog" to be sorted in descending order according to the date of creation, then descending by modification date, and then by title. Type:
      blog: -created, -modified, title  Installation
      Copy the files for this module to /site/modules/ProcessPageListMultipleSorting/ In admin: Modules > Check for new modules. Install Module "Admin Page Tree Multible Sorting". Alternative in ProcessWire 2.4+
      Login to ProcessWire backend and go to Modules Click tab "New" and enter Module Class Name: "ProcessPageListMultipleSorting" Click "Download and Install"   Compatibility   I have currently tested the module only under PW 2.6+, but think that it works on older versions too. Maybe someone can give a feedback.     Download   PW-Repo: http://modules.processwire.com/modules/process-page-list-multiple-sorting/ GitHub: https://github.com/FlipZoomMedia/Processwire-ProcessPageListMultipleSorting     I hope someone can use the module. Have fun and best regards, David
×
×
  • Create New...