Jump to content
pwFoo

FrontendUser: login, logout and register users / members

Recommended Posts

Great! The basic process now works without errors.

Since this is the first Processwire module I am working with, I am still very confused how to finish this. I need to figure out the following:

1. What happens after the user has registered, with the email validation code added to the form? There is no second 'Welcome' email with instructions for the user. Or instead of a confirmation/welcome email you could put a message on the screen after registering: 'Thank you for registering. You can now log in with the username and the password you just picked.' Or log them in automatically after registering. But most users will probably expect a Welcome/confirmation email.

2. How can I assign a role to users upon registration? I have added a custom role "member".

3. How can I add fields to the form, starting with Firstname Lastname? Can Processwire's users db table(s) be extended and used to store entire user accounts - address, phone number, rss feed, favorite color, hobbies, spirit animal, ...?

4. How can I style the form, including the html, not just using the CSS classes/ids? I want to get rid of the listing tags li etc. Would there be a way to just hardcode a form in the template instead of generating it with fu->register()?

5. How can I change the text/style of the validation email? Probably add a template file somewhere?

The answers to this are probably to be found in PW documentation and elsewhere on the forum. Any pointers in the right direction would help.

 

Share this post


Link to post
Share on other sites

Take a look at the frontenduser repo wiki (nickname, default role) and the PW hook documentation for examples how to add / modify features. 

FrontendUser just use PW features (API, InputfieldForm and hooks)! Add own features / plugins by hook into PW / FrontendUser methods (add notification or welcome email after a new user registered successful).

 

Share this post


Link to post
Share on other sites

Thanks pwFoo. I guess I could use this and this as guides then? They are from 2011...

I don't see anything about nickname (?) or Firstname Lastname in the frontenduser repo wiki.

What is the hook for new user registered successful? I can't find it here searching on 'register' or 'registration' or 'user'.

Has anyone implemented a welcome/confirmation email with FrontendUser?

Share this post


Link to post
Share on other sites

You can use examples from the forum or just modify to fit your needs.
There is a mail example inside FrontendUserRegisterEmailValidation.

 

PW hooks: 
https://processwire.com/api/hooks/

FrontendUser Wiki:
https://bitbucket.org/pwFoo/frontenduser/wiki/Register extensions and plugins
https://bitbucket.org/pwFoo/frontenduser/wiki/Login extensions and plugins
https://bitbucket.org/pwFoo/frontenduser/wiki/Code snippets / Examples
https://bitbucket.org/pwFoo/frontenduser/wiki/Documentation#markdown-header-styles-scripts-templates

You can hook the FrontendUser methods auth (=login) and save (=register / save user).
Just hook after FrontendUser save() and check the event return value if user was saved sucessful...

Captain Hook -> search login -> /wire/core/session __login($name, $pass)

 

I love the PW API and hooks ^-^

 

  • Like 2

Share this post


Link to post
Share on other sites

@modifiedcontent

 

Imagine we have 3 pagesHome, Register, Member Area and 3 templates : home, register, member-area.

 

  • In the template home, if the user is not logged in, the login form appear on the homepage - there is also a link to our register page, another for the member area page and the logout link.

Code of home.php :

Spoiler

<?php
// load the module
$fu = $modules->get('FrontendUser');
// if the user is logged in and the get variable "logout" is set, logout the user
if($input->get->logout && $user->isLoggedin()) $fu->logout($pages->get('/')->url);
?>
<html>
<head>
</head>
<body>
<h1>Page: <?php echo $page->title; ?></h1>
<ul>
    <li><a href="<?php echo $pages->get('/register/')->url; ?>">Register</a> <?php if($user->isLoggedin()): ?> | <a href="?logout=logout">Logout</a> <?php endif; ?> </li>
</ul>

<?php
$out = '';
// check if user is logged
if($user->isLoggedin()) {

    $out = "Welcome {$user->name} - You are already logged in...";
    // if the user have the role "member"
    if ($user->hasRole("member")) {
        //redirect the user to the member area
        $session->redirect($pages->get('/member-area/')->url);
        // or do something
    } else {
        // do other stuff for other roles
    }
} else {
    // user is not logged in, show the login form
    $fu->login(['username', 'password']);
    $fu->process($pages->get('/member-area/')->url);
    $out .= $fu->render();
}

echo $out;
?>
</body>
</html>

 

 

 

  • In the register template, we show the registration form. First step, once the form is filled, a validation email is sent to the user. Then if the user go to his mailbox and click to the validation link, he return to our register page and submit the form with the validation token. If everything went smooth, we use a hook before the form is saved to add a role "member" to the user. Then we use a hook after the form is saved to send a confirmation email with the details (username, email, passowrd, welcome message, etc.).

 Code of register.php :

Spoiler

<html>
    <head>
    </head>
    <body>
        <h1>Page: <?php echo $page->title; ?></h1>
        <ul>
            <li><a href="<?php echo $pages->get('/')->url; ?>">Homepage / login</a></li>
        </ul>

        <?php
        $out = '';
        // check if user is logged
        if($user->isLoggedin()) {
            // the user is already logged in, no registration possible, redirect the user to the hmepage
            $session->redirect($pages->get('/')->url);

        } else {
            // user is not logged in then show the registration form
            $fu = $modules->get('FrontendUser'); // load the module
            $fu->register(['username', 'email', 'password', 'emailValidation']); // prepare the form
            // hook to add role
            $fu->addHookBefore('FrontendUser::save', function() use($fu) {
                $fu->userObj->addRole('member'); // add role "member"
            });
            // hook to send an email back to the user with connection/login details
            $fu->addHookAfter('FrontendUser::save', function($event) use($fu, $input) {
                  if($event->return === true) {
                    if(!empty($input->post->password) && !count($fu->form->getErrors())) {
                      $subject = "Your new account at mydomain.com";
                      $emailContentPlain = "Your connection details:\nUsername: {$fu->userObj->name}\nEmail: {$fu->userObj->email}\nPassword: {$input->post->password}";
                      $mail = wireMail();
                      $mail->to($fu->userObj->email);
                      $mail->subject($subject);
                      // plain body
                      $mail->body($emailContentPlain);

                      $mail->send();
                    }
                  }
            });
            $fu->process($pages->get('/')->url);
            $out .= $fu->render();
        }

        echo $out;
        ?>
    </body>
</html>

 

 

 

  • And then in the member-area template, just show welcome message and a logout link. Nothing special here.

Code of member-area.php :

Spoiler

<?php
// load the module
$fu = $modules->get('FrontendUser');
// if the user is logged in and the get variable "logout" is set, logout the user and redirect to the homepage
if($input->get->logout && $user->isLoggedin()) $fu->logout($pages->get('/')->url);
// if the user has not the role "member", redirect him to the homepage
if(!$user->hasRole("member") || !$user->isLoggedin()) $session->redirect($pages->get('/')->url);
?>
<html>
    <head>
    </head>
    <body>
        <h1>Page: <?php echo $page->title; ?></h1>
        <ul>
            <li><?php if($user->isLoggedin()): ?> <a href="?logout=logout">Logout</a> <?php endif; ?> </li>
        </ul>
        <p>Hello <?php echo $user->name; ?> - Welcome to the member Area / profile page / whatever.</p>
    </body>
</html>

 

 

To test it, just create and copy paste the code of each template.

 

FAQ:

Quote

1. [...] But most users will probably expect a Welcome/confirmation email.

Check the hook in the register.php template above.

 

Quote

2. How can I assign a role to users upon registration? I have added a custom role "member".

Check the hook in the register.php template above.

 

Quote

3. How can I add fields to the form, starting with Firstname Lastname? Can Processwire's users db table(s) be extended and used to store entire user accounts - address, phone number, rss feed, favorite color, hobbies, spirit animal, ...?

Read this post and ask for example/help if needed.

 

Quote

4. How can I style the form, including the html, not just using the CSS classes/ids? I want to get rid of the listing tags li etc. Would there be a way to just hardcode a form in the template instead of generating it with fu->register()?

You could do something like that :

$markup = $fu->render();
$markup = str_replace('<ul', '<div', $markup);
$markup = str_replace('<li', '<div', $markup);
$markup = str_replace('</li>', '</div>', $markup);
$markup = str_replace('</ul>', '</div>', $markup);
$out .= $markup;

(I am sure there is a better way to do it)

 

Quote

5. How can I change the text/style of the validation email? Probably add a template file somewhere?

You can modify the file emailValidation.php or use your own in /site/modules/FrontendUser/templates.

 

 

Hope it help :)

Edited by flydev
FAQ
  • Like 5

Share this post


Link to post
Share on other sites

Yes, that helps a lot, especially the addHookAfter bit for the confirmation email. Thanks flydev & pwFoo!

Below is my one page working version, as a minumum starting point:

Spoiler

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

$redirectDestination = htmlentities($_SERVER['REQUEST_URI']);

$fu->addHookBefore('save', function($event) {
    $user = wire('fu')->userObj;
    $user->addRole('member');
});

$fu->addHookAfter('FrontendUser::save', function($event) use($fu, $input) {
	if($event->return === true) {
		if(!empty($input->post->password) && !count($fu->form->getErrors())) {
			$subject = "Welcome - your new account at mydomain.com";
			$emailContentPlain = "Your connection details:\nUsername: {$fu->userObj->name}\nEmail: {$fu->userObj->email}\nPassword: {$input->post->password}";
			$mail = wireMail();
			$mail->to($fu->userObj->email);
			$mail->subject($subject);
			$mail->body($emailContentPlain);
			$mail->send();
		}
	}
});

// Login with the email address instead of the username
$fu->addHookBefore('FrontendUser::auth', function($event) {
        $email = wire('fu')->form->fhValue('username', 'email');
        $loginUser = wire('users')->get("email={$email}");

        if ($loginUser instanceof User && !$loginUser->isGuest()) {
            $userObj = $event->arguments[0];
            $userObj->name = $loginUser->name;
        }
});

if ($user->isGuest()) {
$fu->register(array('username', 'email', 'emailValidation', 'password'));
$fu->process($redirectDestination);
echo $fu->render();

echo 'or log in here if you already have an account';
echo $fu->login(null, $redirectDestination);
}

if($user->isLoggedin()) {
	if (isset($_GET['logout'])) $fu->logout($redirectDestination);
	echo "<a href='?logout'>log out</a>";
}

Any suggestions for improvements? Is that log out link the cleanest way to do it?

Share this post


Link to post
Share on other sites
14 minutes ago, modifiedcontent said:

.flydev, how do you put a big block of code in a 'Reveal hidden contents' block?

The button with the eye on the right, labelled

Spoiler

Spoiler

:P

  • Like 3

Share this post


Link to post
Share on other sites

Hello pwFoo,

Thank you for this suite of modules - I've just been trying them out for the first time and they look very useful. I particularly like the email validation portion of this.

One small observation though, when registering a new user and using a name or email that already exists, all the entered values are lost on unsuccessful form submission. I think it would be helpful to keep the value of any field that is not in error. So, if a user typed an in-use name, but the email was OK, then we should keep the email field and only clear the name field.

Thank you!

Share this post


Link to post
Share on other sites

I'll take a look... don't know when, but I think I have to change the clear session values part...

            // Clear session values
            wire('session')->remove('registerToken');
            wire('session')->remove('registerUsername');
            wire('session')->remove('registerEmail');

https://bitbucket.org/pwFoo/frontenduser/src/0070dc3106945198ac438bab3ab742b1784080e9/FrontendUser/FrontendUserRegisterEmailValidation.module?at=master&fileviewer=file-view-default#FrontendUserRegisterEmailValidation.module-165

https://bitbucket.org/pwFoo/frontenduser/src/0070dc3106945198ac438bab3ab742b1784080e9/FrontendUser/FrontendUserRegisterEmailValidation.module?at=master&fileviewer=file-view-default#FrontendUserRegisterEmailValidation.module-143

It should check and take care about field errors first.

Share this post


Link to post
Share on other sites

Trying to add firstname, lastname fields now. Here is what I have so far, following an earlier post suggested by flydev:

Spoiler

<?php
$fu = $modules->get('FrontendUser');

$redirectDestination = htmlentities($_SERVER['REQUEST_URI']);

$firstname = $modules->get('InputfieldText');
$firstname->label = 'First name';
$firstname->attr('id+name','firstname');
$firstname->required = 1;

$firstname->addHookAfter('processInput', function($event) {
   $field = $event->object;
   $mySanitizedCustomInput = wire('fu')->form->fhValue($field->name);
   wire('fu')->userObj->firstname = $mySanitizedCustomInput;
});

$fu->addHookBefore('save', function($event) {
    $user = wire('fu')->userObj;
    $user->addRole('member');
});

$fu->addHookAfter('FrontendUser::save', function($event) use($fu, $input) {
	if($event->return === true) {
		if(!empty($input->post->password) && !count($fu->form->getErrors())) {
			$subject = "Welcome - your new account at mydomain.com";
			$emailContentPlain = "Your connection details:\nUsername: {$fu->userObj->name}\nEmail: {$fu->userObj->email}\nPassword: {$input->post->password}";
			$mail = wireMail();
			$mail->to($fu->userObj->email);
			$mail->subject($subject);
			$mail->body($emailContentPlain);
			$mail->send();
		}
	}
});

// Login with the email address instead of the username
$fu->addHookBefore('FrontendUser::auth', function($event) {
        $email = wire('fu')->form->fhValue('username', 'email');
        $loginUser = wire('users')->get("email={$email}");

        if ($loginUser instanceof User && !$loginUser->isGuest()) {
            $userObj = $event->arguments[0];
            $userObj->name = $loginUser->name;
        }
});

if ($user->isGuest()) {
$fu->register(array($firstname,'username', 'email', 'emailValidation', 'password'));
$fu->process($redirectDestination);
echo $fu->render();

echo 'or log in here if you already have an account';
echo $fu->login(null, $redirectDestination);
}

if($user->isLoggedin()) {
	if (isset($_GET['logout'])) $fu->logout($redirectDestination);
	echo "<a href='?logout'>log out</a>";
	echo '<h3>Hello '. $user->firstname .'</h3>';
}
?>

 

This sort of works, but the firstname is not filled in when you click on the email validation link; the user has to manually add it again. It should be stored along with the username, right?

Is 'addHookAfter ...' the wrong hook? Is it essentially the same problem netcarver posted about here?

Will I have to add the same lines like the $firstname stuff for each custom field or is there a way to consolidate that, process all custom fields with one function?

 

Share this post


Link to post
Share on other sites

At the moment I think about a rewrite and code cleanup, but have no time to do it.

The return value of process() method could cause a strange behavior because it returns "true" also if the form wasn't submitted because of the "return $this" for chaining 

    public function process($redirect) {
        if ($this->form->fhProcessForm()) {
            switch ($this->action) {
                case 'Login':
                    $result = $this->auth($this->userObj);
                  break;
                case 'Register':
                    $result = $this->save($this->userObj);
                  break;
            }
            if ($result === true) {
                $this->session->redirect($redirect, false);     // User sucessfully registered
            }
            else {
                $this->form->fhSubmitBtn->error($result);       // Save user failed?
            }        
        }
        return $this;
    }

 

  • Like 1

Share this post


Link to post
Share on other sites

I want to generate the username from a real/full name; firstname + lastname. How can I get onkeyup into the fullname input field?

This didn't work:

$fullname = $modules->get('InputfieldText');
$fullname->label = 'Full name';
$fullname->attr('id+name','fullname');
$fullname->required = 1;
$fullname->onkeyup='generateusername()';

Question now asked here with the username autogenerating javascript included.

Share this post


Link to post
Share on other sites

Not the module, but PW. Just hook into form processing / user registration and generate the needed value before the user object will be saved.

The module methods are hookable too.

  • Like 1

Share this post


Link to post
Share on other sites

I can't figure out the forms API and hookable etc. I only have very rudimentary PHP knowledge.

I had copied and pasted this together to get a custom realname/fullname field:

Spoiler

$fullname = $modules->get('InputfieldText');
$fullname->label = 'Full name';
$fullname->attr('id+name','fullname');
$fullname->required = 1;

$fullname->addHookAfter('processInput', function($event) {
   $field = $event->object;
   $mySanitizedCustomInput = wire('fu')->form->fhValue($field->name);
   wire('fu')->userObj->fullname = $mySanitizedCustomInput;
});

$fu->addHookBefore('save', function($event) {
    $user = wire('fu')->userObj;
    $user->addRole('member');
});

>

But the fullname field is not stored. How do you store custom fields with userObj? I can't find any clear code examples anywhere that don't go off into a million different directions.

Should I add something under $fu->addHookBefore, like $user->fullname or something like that?

What is fhValue($field->name)? What "name" is that? Is that the username? I tried it changed to $field->fullname, but that didn't do anything.

Adding a new user apparently looks something like this:

Spoiler

$u = new User();
$u->name = $form->get('username')->value;
$u->pass = $form->get('password')->value;
$u->email = $form->get('email')->value;
$u->addRole('guest');

 

So I guess I have to define fullname "somewhere" using $form->get('fullname')->value?

I have no idea what the module does and what I am supposed to code together myself and how it is all supposed to hang together. Completely lost. Getting this ready for "production" is starting to take way too long.

Share this post


Link to post
Share on other sites

The module just uses PW features. So it uses the default user template. You need to add custom fields to save additional attributes!

 

Share this post


Link to post
Share on other sites

Yes, I get that. I have a custom fullname field, but can't find anywhere how to store that value and how that works in combination with your module. PW features and hookable etc. may be completely obvious to you, but this is the first PW module I am working with.

I had added the fullname field to the template. Should I also add a username field to the template? Or does the module take care of that?

There is this error log in admin:

Error: Exception: Method FrontendUser::fullnameRegister does not exist or is not callable in this context (in /home/mysitepath/wire/core/Wire.php line 410)

Share this post


Link to post
Share on other sites
12 hours ago, modifiedcontent said:

Yes, I get that. I have a custom fullname field, but can't find anywhere how to store that value and how that works in combination with your module.

Hi,

you first need a backend template for your users that has the fields you want to work with.

think of the fields in a template as the columns of a row of data for the 'table' (here: "user", most times "page") (actually this is not how it works under the hood, but it helps to think of it this way in the beginning); the standard user template just has the minimum (data)fields required, aka name, password, and email and a bit of meta things. so to work with your new field 'fullname', you need to create a field 'fullname' in the admin, then apply this field to a new template (for example 'user_extended'; this template should have all the fields of the regular user template, plus your newly created one(s)) or. You can extend the user-template with your new field(s), by editing the user template (and setting the list to include system fields).

once you have the template applied to the 'user'Once your field is in the user template, your $userObject->fullname = blablainputfield->fullname will work (assuming that the field for the full name in the template is named 'fullname').

hope this helps to get you started,

Tom

Share this post


Link to post
Share on other sites

Hi, I would like to do a register form with email pre-registration validation, but without the username field.

Instead the username should be the email sanitzed as a pageName.

I have the following code right now:

<?php namespace ProcessWire;

// prepare register form
// Additional email pre-register validation plugin (built-in)
$fu->register(array('email', 'emailValidation', 'password'));

$fu->form->setMarkup($form_markup);
$fu->form->setClasses = ($form_classes);

$fu->addHookBefore('FrontendUser::save', function ($event) {
    $user = wire('fu')->userObj;
    $form = wire('fu')->form;
    if (!count($form->getErrors())) {
        // set the username to sanitized email value
//        $user->name = $form->fhValue('email', 'pageName');
        $user->addRole('editor');
    }
});

// process register / form submit
$fu->process($profile_url);
$register_form = $fu->render();
$view->set('registerForm', $register_form); // this is for Twig

But when I submit that form I get an error:

Call to a member function getErrors() on null in line 94 of FrontendUserRegisterEmailValidation.module

I think it is because in the function "hookRegisterFormAfterProcess" there is line 84:

$user = $form->get('username');

As I send no username, this can not work. So how can I make it work without touching the FrontendUserRegisterEmailValidation.module?

Thanks in advance.

  • Like 1

Share this post


Link to post
Share on other sites

@jmartsch, actually go without a username entirely would probably require a rewrite of this module and maybe PW core itself.

I am trying to get rid of the username field by autogenerating a username based on the full name input and then make the username field hidden; there is still a username, but only for internal system purposes. I use this javascript:

Spoiler

<script>
$("#fullname").bind("keyup change", function(e) {
	var input=$(this).val();
	
	input = input.replace(/^\s+|\s+$/g, ''); // trim
	input = input.toLowerCase();
  
  // replace diacritics, weird accent letters, swap ñ for n, è for e, etc
	var diacritics = [
    {char: 'A', base: /[\300-\306]/g},
    {char: 'a', base: /[\340-\346]/g},
    {char: 'E', base: /[\310-\313]/g},
    {char: 'e', base: /[\350-\353]/g},
    {char: 'I', base: /[\314-\317]/g},
    {char: 'i', base: /[\354-\357]/g},
    {char: 'O', base: /[\322-\330]/g},
    {char: 'o', base: /[\362-\370]/g},
    {char: 'U', base: /[\331-\334]/g},
    {char: 'u', base: /[\371-\374]/g},
    {char: 'N', base: /[\321]/g},
    {char: 'n', base: /[\361]/g},
    {char: 'C', base: /[\307]/g},
    {char: 'c', base: /[\347]/g}
	]

	diacritics.forEach(function(letter){
    input = input.replace(letter.base, letter.char);
	});
	
	input = input.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
	.replace(/\s+/g, '') // collapse whitespace and replace by -
	.replace(/-+/g, ''); // collapse dashes

	$("#username").val(input);
});
</script>

 

 

Share this post


Link to post
Share on other sites

It could also be done with a PW hook ;)

Make username hidden and not required. Hook into form process and set the required user object value server side.

  • Like 1

Share this post


Link to post
Share on other sites

@modifiedcontent Thank you for your suggestion. But relying on JavaScript is not good. I also think that a rewrite is not needed. I don´t want no username. I just don´t want the username in the form because it could be manipulated. The username should be the same as the email address, but sanitized as pageName.

 

  • Like 1

Share this post


Link to post
Share on other sites

@pwFoo, could you give a few more pointers how to do that? This 'do it with a PW hook' is still not obvious to me at all. Is there a code example somewhere? If it is possible to have a registration process with just email, that would be great. I'd like to avoid javascript - good point @jmartsch.

Share this post


Link to post
Share on other sites

@pwFoo Could you give me an example how to do this? I think this could be of help for others too.

EDIT: pls note that I do not want to send the username with the form, because it can be manipulated. See my previous post.

  • Like 1

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 David Karich
      ProcessWire InputfieldRepeaterMatrixDuplicate
      Thanks to the great ProModule "RepeaterMatrix" I have the possibility to create complex repeater items. With it I have created a quite powerful page builder. Many different content modules, with many more possible design options. The RepeaterMatrix module supports the cloning of items, but only within the same page. Now I often have the case that very design-intensive pages and items are created. If you want to use a content module on a different page (e.g. in the same design), you have to rebuild each item manually every time.
      This module extends the commercial ProModule "RepeaterMatrix" by the function to duplicate repeater items from one page to another page. The condition is that the target field is the same matrix field from which the item is duplicated. This module is currently understood as proof of concept. There are a few limitations that need to be considered. The intention of the module is that this functionality is integrated into the core of RepeaterMatrix and does not require an extra module.
      Check out the screencast
      What the module can do
      Duplicate multible repeater items from one page to another No matter how complex the item is Full support for file and image fields Multilingual support Support of Min and Max settings Live synchronization of clipboard between multiple browser tabs. Copy an item and simply switch the browser tab to the target page and you will immediately see the past button Support of multiple RepeaterMatrix fields on one page Configurable which roles and fields are excluded Configurable dialogs for copy and paste Duplicated items are automatically pasted to the end of the target field and set to hidden status so that changes are not directly published Automatic clipboard update when other items are picked Automatically removes old clipboard data if it is not pasted within 6 hours Delete clipboard itself by clicking the selected item again Benefit: unbelievably fast workflow and content replication What the module can't do
      Before an item can be duplicated in its current version, the source page must be saved. This means that if you make changes to an item and copy this, the old saved state will be duplicated Dynamic loading is currently not possible. Means no AJAX. When pasting, the target page is saved completely No support for nested repeater items. Currently only first level items can be duplicated. Means a repeater field in a repeater field cannot be duplicated. Workaround: simply duplicate the parent item Dynamic reloading and adding of repeater items cannot be registered. Several interfaces and events from the core are missing. The initialization occurs only once after the page load event Changelog
      2.0.0
      Feature: Copy multiple items at once! The fundament for copying multiple items was created by @Autofahrn - THX! Feature: Optionally you can disable the copy and/or paste dialog Bug fix: A fix suggestion when additional and normal repeater fields are present was contributed by @joshua - THX! 1.0.4
      Bug fix: Various bug fixes and improvements in live synchronization Bug fix: Items are no longer inserted when the normal save button is clicked. Only when the past button is explicitly clicked Feature: Support of multiple repeater fields in one page Feature: Support of repeater Min/Max settings Feature: Configurable roles and fields Enhancement: Improved clipboard management Enhancement: Documentation improvement Enhancement: Corrected few typos #1 1.0.3
      Feature: Live synchronization Enhancement: Load the module only in the backend Enhancement: Documentation improvement 1.0.2
      Bug fix: Various bug fixes and improvements in JS functions Enhancement: Documentation improvement Enhancement: Corrected few typos 1.0.1
      Bug fix: Various bug fixes and improvements in the duplication process 1.0.0
      Initial release Support this module
      If this module is useful for you, I am very thankful for your small donation: Donate 5,- Euro (via PayPal – or an amount of your choice. Thank you!)
      Download this module (Version 2.0.0)
      > Github: https://github.com/FlipZoomMedia/InputfieldRepeaterMatrixDuplicate
      > PW module directory: https://modules.processwire.com/modules/inputfield-repeater-matrix-duplicate/
      > Old stable version (1.0.4): https://github.com/FlipZoomMedia/InputfieldRepeaterMatrixDuplicate/releases/tag/1.0.4
    • By Robin S
      A new module that hasn't had a lot of testing yet. Please do your own testing before deploying on any production website.
      Custom Paths
      Allows any page to have a custom path/URL.
      Note: Custom Paths is incompatible with the core LanguageSupportPageNames module. I have no experience working with LanguageSupportPageNames or multi-language sites in general so I'm not in a position to work out if a fix is possible. If anyone with multi-language experience can contribute a fix it would be much appreciated!
      Screenshot

      Usage
      The module creates a field named custom_path on install. Add the custom_path field to the template of any page you want to set a custom path for. Whatever path is entered into this field determines the path and URL of the page ($page->path and $page->url). Page numbers and URL segments are supported if these are enabled for the template, and previous custom paths are managed by PagePathHistory if that module is installed.
      The custom_path field appears on the Settings tab in Page Edit by default but there is an option in the module configuration to disable this if you want to position the field among the other template fields.
      If the custom_path field is populated for a page it should be a path that is relative to the site root and that starts with a forward slash. The module prevents the same custom path being set for more than one page.
      The custom_path value takes precedence over any ProcessWire path. You can even override the Home page by setting a custom path of "/" for a page.
      It is highly recommended to set access controls on the custom_path field so that only privileged roles can edit it: superuser-only is recommended.
      It is up to the user to set and maintain suitable custom paths for any pages where the module is in use. Make sure your custom paths are compatible with ProcessWire's $config and .htaccess settings, and if you are basing the custom path on the names of parent pages you will probably want to have a strategy for updating custom paths if parent pages are renamed or moved.
      Example hooks to Pages::saveReady
      You might want to use a Pages::saveReady hook to automatically set the custom path for some pages. Below are a couple of examples.
      1. In this example the start of the custom path is fixed but the end of the path will update dynamically according to the name of the page:
      $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'my_template') { $page->custom_path = "/some-custom/path-segments/$page->name/"; } }); 2. The Custom Paths module adds a new Page::realPath method/property that can be used to get the "real" ProcessWire path to a page that might have a custom path set. In this example the custom path for news items is derived from the real ProcessWire path but a parent named "news-items" is removed:
      $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'news_item') { $page->custom_path = str_replace('/news-items/', '/', $page->realPath); } }); Caveats
      The custom paths will be used automatically for links created in CKEditor fields, but if you have the "link abstraction" option enabled for CKEditor fields (Details > Markup/HTML (Content Type) > HTML Options) then you will see notices from MarkupQA warning you that it is unable to resolve the links.
      Installation
      Install the Custom Paths module.
      Uninstallation
      The custom_path field is not automatically deleted when the module is uninstalled. You can delete it manually if the field is no longer needed.
       
      https://github.com/Toutouwai/CustomPaths
      https://modules.processwire.com/modules/custom-paths/
    • By teppo
      Hey folks!
      I'm happy to finally introduce a project I've been working on for quite a while now: it's called Wireframe, and it is an output framework for ProcessWire.
      Note that I'm posting this in the module development area, maily because this project is still in rather early stage. I've built a couple of sites with it myself, and parts of the codebase have been powering some pretty big and complex sites for many years now, but this should still be considered a soft launch 🙂
      --
      Long story short, Wireframe is a module that provides the "backbone" for building sites (and apps) with ProcessWire using an MVC (or perhaps MVVM... one of those three or four letter acronyms anyway) inspired methodology. You could say that it's an output strategy, but I prefer the term "output framework", since in my mind the word "strategy" means something less tangible. A way of doing things, rather than a tool that actually does things.
      Wireframe (the module) provides a basic implementation for some familiar MVC concepts, such as Controllers and a View layer – the latter of which consists of layouts, partials, and template-specific views. There's no "model" layer, since in this context ProcessWire is the model. As a module Wireframe is actually quite simple – not even nearly the biggest one I've built – but there's still quite a bit of stuff to "get", so I've put together a demo & documentation site for it at https://wireframe-framework.com/.
      In addition to the core module, I'm also working on a couple of site profiles based on it. My current idea is actually to keep the module very light-weight, and implement most of the "opinionated" stuff in site profiles and/or companion modules. For an example MarkupMenu (which I released a while ago) was developed as one of those "companion modules" when I needed a menu module to use on the site profiles.
      Currently there are two public site profiles based on Wireframe:
      site-wireframe-docs is the demo&docs site mentioned above, just with placeholder content replaced with placeholder content. It's not a particularly complex site, but I believe it's still a pretty nice way to dig into the Wireframe module. site-wireframe-boilerplate is a boilerplate (or starter) site profile based on the docs site. This is still very much a work in progress, but essentially I'm trying to build a flexible yet full-featured starter profile you can just grab and start building upon. There will be a proper build process for resources, it will include most of the basic features one tends to need from site to site, etc. --
      Requirements and getting started:
      Wireframe can be installed just like any ProcessWire module. Just clone or download it to your site/modules/ directory and install. It doesn't, though, do a whole lot of stuff on itself – please check out the documentation site for a step-by-step guide on setting up the directory structure, adding the "bootstrap file", etc. You may find it easier to install one of the site profiles mentioned above, but note that this process involves the use of Composer. In the case of the site profiles you can install ProcessWire as usual and download or clone the site profile directory into your setup, but after that you should run "composer install" to get all the dependencies – including the Wireframe module – in place. Hard requirements for Wireframe are ProcessWire 3.0.112 and PHP 7.1+. The codebase is authored with current PHP versions in mind, and while running it on 7.0 may be possible, anything below that definitely won't work. A feature I added just today to the Wireframe module is that in case ProcessWire has write access to your site/templates/ directory, you can use the module settings screen to create the expected directories automatically. Currently that's all, and the module won't – for an example – create Controllers or layouts for you, so you should check out the site profiles for examples on these. (I'm probably going to include some additional helper features in the near future.)
      --
      This project is loosely based on an earlier project called pw-mvc, i.e. the main concepts (such as Controllers and the View layer) are very similar. That being said, Wireframe is a major upgrade in terms of both functionality and architecture: namespaces and autoloader support are now baked in, the codebase requires PHP 7, Controllers are classes extending \Wireframe\Controller (instead of regular "flat" PHP files), implementation based on a module instead of a collection of drop-in files, etc.
      While Wireframe is indeed still in a relatively early stage (0.3.0 was launched today, in case version numbers matter) for the most part I'm happy with the way it works, and likely won't change it too drastically anytime soon – so feel free to give it a try, and if you do, please let me know how it went. I will continue building upon this project, and I am also constantly working on various side projects, such as the site profiles and a few unannounced helper modules.
      I should probably add that while Wireframe is not hard to use, it is more geared towards those interested in "software development" type methodology. With future updates to the module, the site profiles, and the docs I hope to lower the learning curve, but certain level of "developer focus" will remain. Although of course the optimal outcome would be if I could use this project to lure more folks towards that end of the spectrum... 🙂
      --
      Please let me know what you think – and thanks in advance!
    • By tcnet
      PageViewStatistic for ProcessWire is a module to log page visits of the CMS. The records including some basic information like IP-address, browser, operating system, requested page and originate page. Please note that this module doesn't claim to be the best or most accurate.
      Advantages
      One of the biggest advantage is that this module doesn't require any external service like Google Analytics or similar. You don't have to modify your templates either. There is also no JavaScript or image required.
      Disadvantages
      There is only one disadvantage. This module doesn't record visits if the browser loads the page from its browser cache. To prevent the browser from loading the page from its cache, add the following meta tags to the header of your page:
      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> How to use
      The records can be accessed via the Setup-menu of the CMS backend. The first dropdown control changes the view mode. There are 4 different view modes.
      View mode "Day" shows all visits of the selected day individually with IP-address, browser, operating system, requested page and originate page. Click the update button to see new added records. View mode "Month" shows the total of all visitors per day from the first to the last day of the selected month. View mode "Year" shows the total of all visitors per month from the first to the last month of the selected year. View mode "Total" shows the total of all visitors per year for all recorded years. Please note that multiple visits from the same IP address within the selected period are counted as a single visitor.
      Settings
      You can access the module settings by clicking the Configuration button at the bottom of the records page. The settings page is also available in the menu: Modules->Configure->ProcessPageViewStat.
      IP2Location
      This module uses the IP2Location database from: http://www.ip2location.com. This database is required to obtain the country from the IP address. IP2Location updates this database at the begin of every month. The settings of ProcessPageViewStat offers the ability to automatically download the database monthly. Please note, that automatically download will not work if your webspace doesn't allow allow_url_fopen.
      Dragscroll
      This module uses DragScroll. A JavaScript available from: http://github.com/asvd/dragscroll. Dragscroll adds the ability in view mode "Day" to drag the records horizontally with the mouse pointer.
      parseUserAgentStringClass
      This module uses the PHP class parseUserAgentStringClass available from: http://www.toms-world.org/blog/parseuseragentstring/. This class is required to filter out the browser type and operating system from the server request.
      Special Feature
      PageViewStatistic for ProcessWire can record the time a visitor viewed the page. This feature is deactivated by default. To activate open the module configuration page and activate "Record view time". If activated you will find a new column "S." in the records which means the time of view in seconds. With every page request, a Javascript code is inserted directly after the <body> tag. Every time the visitor switches to another tab or closes the tab, this script reports the number of seconds the tab was visible. The initial page request is recorded only as a hyphen (-).
       
    • By MoritzLost
      This module allows you to integrate hCaptcha bot / spam protection into ProcessWire forms. hCaptcha is a great alternative to Google ReCaptcha, especially if you are in the EU and need to comply with privacy regulations.

      The development of this module is sponsored by schwarzdesign.
      The module is built as an Inputfield, allowing you to integrate it into any ProcessWire form you want. It's primarily intended for frontend forms and can be added to Form Builder forms for automatic spam protection. There's a step-by-step guide for adding the hCaptcha widget to Form Builder forms in the README, as well as instructions for API usage.
      Features
      Inputfield that displays an hCaptcha widget in ProcessWire forms. The inputfield verifies the hCaptcha response upon submission, and adds a field error if it is invalid. All hCaptcha configuration options for the widget (theme, display size etc) can be changed through the inputfield configuration, as well as programmatically. hCaptcha script options can be changed through a hook. Error messages can be translated through ProcessWire's site translations. hCaptcha secret keys and site-keys can be set for each individual inputfield or globally in your config.php. Error codes and failures are logged to help you find configuration errors. Please check the README for setup instructions.
      Links
      Github Repository and documentation InputfieldHCaptcha in the module directory Screenshots (configuration)

      Screenshots (hCaptcha widget)

       
       

       
×
×
  • Create New...