Jump to content

Disallowing Names for Pages


ethanbeyer
 Share

Recommended Posts

For some further background on this issue, please see this forum post.

I have a template called "subdomain" - and for pages with that template, I need to throw an error if the name is something like "edit" or "admin" or "www" or "processwire", because all of those subdomains are already in use, and I want to prevent URL collision.

Is there a method or a hook or something that I'm missing that sets a name as disallowed/blacklisted/native?

Thanks in advance!

Link to comment
Share on other sites

Hello @ethfun,

you could define a list of allowed URL segments and then write the logic inside your template, like f.e.:

if ($input->urlSegment1 == 'subdomain-one') {
	// Show first subdomain
} else if($input->urlSegment1 == 'subdomain-two') {
	// Show second subdomain
} else {
	throw new Wire404Exception(); // Show 404 page
}

If you are using PW3 and are looking for a cleaner way to separate the contents of your subdomains, you may be interested in using multi-instance;)

Regards, Andreas

Link to comment
Share on other sites

@ethfun, if I understand right you would like to validate the page name during the Add Page process.

This ought to be possible with a hook to ProcessPageAdd::processInput or InputfieldPageName::processInput, but stuffed if I can get PW to give a field error and return to Add Page; the error is displayed but the page is still added. I thought you could set an error to the inputfield...

$my_field->error('That value is not allowed');

...and the form wouldn't validate but I can't get that work for Add Page. Hopefully someone knows how to do this.

BTW, members without a Form Builder license will not be able to read the thread you linked to with the background info. Might be good to include the details here.

  • Like 4
Link to comment
Share on other sites

You could also override the javascript name checker so that you could warn users before they save the page. Take a look at this module: https://github.com/adrianbj/PageRenameOptions which also overrides that JS - it might help to get you started on the right path more quickly.

Obviously this approach should be in addition to server-side checking, rather than a replacement for it :)

  • Like 3
Link to comment
Share on other sites

I have made some major progress - but I could use some help for that last little push.

@adrian, I've looked over your code for the PageRenameOptions module extensively, and apart from learning a lot, I am going to install that module on every single PW site I have. So thank you!!

What I decided to do was to write a small module that handles this issue. See below:

<?php

use Helpers;

class ProcessPageBlacklisted extends WireData implements Module, ConfigurableModule
{
    protected $configFields;

    /**
     * getModuleInfo is a module required by all modules to tell ProcessWire about them
     *
     * @return array
     *
     */
    public static function getModuleInfo()
    {
        return array(
            'title' => 'Blacklisted Pages',
            'version' => 100,
            'summary' => 'Creates an array of Blacklisted Pages that prevents the user from making pages that shouldn\'t exist.',
            'href' => '',
            'singular' => true,
            'autoload' => true
        );
    }


    /**
     * Init Function - loads scripts via hooks
     */
    public function init()
    {
        // Add the Hooks to these two pages to add the JS
        $this->addHookBefore("ProcessPageEdit::buildForm", $this, "addScripts");
        $this->addHookBefore("ProcessPageAdd::buildForm", $this, "addScripts");
    }


    /**
     * Function to add the relevant Javascript to the Add and Edit Page screens
     */
    protected function addScripts(HookEvent $event)
    {
        $conf = $this->getModuleInfo();
        $version = (int) $conf['version'];
        return wire('config')->scripts->add(
            $this->config->urls->ProcessPageBlacklisted."ProcessPageBlacklisted.js?v={$version}"
        );
    }


    public function execute()
    {
        $name = $this->wire('sanitizer')->pageNameUTF8($this->wire('input')->get('name')); 
        if(!strlen($name)) return '';
        
        $blacklisted_names = explode("\n", $this->data['blacklisted_names']);

        if(in_array($name, $blacklisted_names)) {
            $out = "<span class='taken ui-state-error-text'><i class='fa fa-exclamation-triangle'></i> " . $this->_('This name is not allowed!') . "</span>";    
        }
        
        return $out; 
    }

    public function getModuleConfigInputfields(array $data)
    {
        $form = new InputfieldWrapper();
        $f = wire('modules')->get('InputfieldTextarea');
        $f->name = 'blacklisted_names'; 
        $f->label = __('Blacklisted Page Names');
        $f->value = $data['blacklisted_names'];
        $form->add($f);

        return $form;
    }
}

I'm making pretty heavy use of the ProcessPageAdd module, which has also been very helpful to look through.

I copied the JS file from ProcessPageAdd and made a few changes to it, and I believe everything will work as planned once I figure out how to get the script to actually interface with the module itself through the execute() method. I keep reading Docs and different forum postings, but I'm stumped here.

I expected that having a class called ProcessPageBlacklisted would be reachable through "admin/page/blacklisted", the output of the page being created by execute(). Apparently, I'm wrong. The javascript looks at what's in the name box, does an ajax call to "admin/page/blacklisted", and returns:

` {"error":false,"message":"Unrecognized path"} `

Can someone tell me what I need to do in order to get the output from the execute() function?

Thank youuuuu...

 

  • Like 1
Link to comment
Share on other sites

8 hours ago, ethfun said:

If someone typed in "www" as the name, I'd like to throw an error that says that that name is not allowed, and not save the page.

Here is a server-side alternative to (or backup for) the JS validation.

$this->addHookBefore('ProcessPageAdd::processInput', function($event) {
    $form = $event->arguments('form');
    $input = $this->input;
    $sanitizer = $this->sanitizer;

    $template = $sanitizer->int($input->post->template);
    if($template !== 43) return; // the ID of the template you want to limit page names for
    $name = $sanitizer->pageName($input->post->_pw_page_name);
    $parent_id = $sanitizer->int($input->post->parent_id);
    $uri = $_SERVER['REQUEST_URI'];
    
    $blacklist = ['cat', 'dog', 'hamster']; // your blacklist
    if(in_array($name, $blacklist) ) {
        $name_field = $form->children->get('_pw_page_name');
        $error = "The page name '$name' is reserved. Please choose a different name.";
        $name_field->error($error);
        $this->session->redirect("{$uri}?parent_id=$parent_id");
    }
});

A little awkward but does the job. You could incorporate into a module to get a configurable template selection and name blacklist.

  • Like 3
Link to comment
Share on other sites

 

1 hour ago, ethfun said:

@adrian, I've looked over your code for the PageRenameOptions module extensively, and apart from learning a lot, I am going to install that module on every single PW site I have. So thank you!!

You're welcome and glad you like the module - I know I can't live without it :)

1 hour ago, ethfun said:

I expected that having a class called ProcessPageBlacklisted would be reachable through "admin/page/blacklisted",

Process modules need to extend "Process", not "WireData". You also need to tell it to create the admin/page/setup/blacklisted page. You can do this manually in the install method, but there is a much easier option which you can read about here: https://processwire.com/blog/posts/august-2014-core-updates-4/#process-modules-are-now-a-lot-smarter

Am I right in assuming the idea of the Process module is to list (or allow editing) of the blacklisted page names?

Let us know if you still need help.

PS - there are lots of modules in the modules directory that are labeled as Process modules but really aren't. I am as guilty of this as anyone - I just didn't understand it all in the beginning and don't want to rename them now as it would break user's updates.

 

  • Like 1
Link to comment
Share on other sites

On 11/22/2016 at 5:39 PM, Robin S said:

Here is a server-side alternative to (or backup for) the JS validation.


$this->addHookBefore('ProcessPageAdd::processInput', function($event) {
    $form = $event->arguments('form');
    $input = $this->input;
    $sanitizer = $this->sanitizer;

    $template = $sanitizer->int($input->post->template);
    if($template !== 43) return; // the ID of the template you want to limit page names for
    $name = $sanitizer->pageName($input->post->_pw_page_name);
    $parent_id = $sanitizer->int($input->post->parent_id);
    $uri = $_SERVER['REQUEST_URI'];
    
    $blacklist = ['cat', 'dog', 'hamster']; // your blacklist
    if(in_array($name, $blacklist) ) {
        $name_field = $form->children->get('_pw_page_name');
        $error = "The page name '$name' is reserved. Please choose a different name.";
        $name_field->error($error);
        $this->session->redirect("{$uri}?parent_id=$parent_id");
    }
});

A little awkward but does the job. You could incorporate into a module to get a configurable template selection and name blacklist.

Looking at this, it's got a lot of what I needed! I added a few other little features, but thank you for this code! It's been very helpful!

 

Quote

Process modules need to extend "Process", not "WireData". You also need to tell it to create the admin/page/setup/blacklisted page. You can do this manually in the install method, but there is a much easier option which you can read about here: https://processwire.com/blog/posts/august-2014-core-updates-4/#process-modules-are-now-a-lot-smarter

@adrian I never would've found this on my own - thank you!!

I never would've been able to see how Process modules worked without this file, either: https://github.com/ryancramerdesign/ProcessHello/blob/master/ProcessHello.module.php

Lastly, here's the repo for the module I made - I'd love any feedback (There are definitely some janky bits)!
https://github.com/ethanbeyer/ProcessWire-Blacklisted-Page-Names-Module

  • Like 3
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...