Jump to content
Noel Boss

Best Practice to determine if admin from init method?

Recommended Posts

👋 PW Pros…

I have some hooks that I need to bind at the init phase (or even __construct) and I was wondering, and I couldn't find a good and simple way to determine if I'm in the admin. Would be nice if there is a reliable short option to do so, but I can't seem to find one… Is there a coherent way to tell this no matter where I am?

Right now, I use the following method inside one of my modules:

public function isAdmin($page = null)
	{

		if (
			strpos($this->input->url, $this->urls->admin) !== false
			|| $this->process instanceof ProcessPageList
			|| $this->process instanceof ProcessPageEdit
			|| ($page instanceof Page && $page->rootParent->id == $this->config->adminRootPageID)
		) {
			return true;
		}
		return false;
	}

@ryan wouldn't it be nice to have something like wire()->isAdmin(); like wire()->user->isLoggedin(); to tell if we are in admin – very early on (probably even in __construct() phase of modules?

  • Like 1

Share this post


Link to post
Share on other sites

Doesn't this work?

if ($this->page->template == 'admin') {
    echo "in admin";
} else {
    echo "not in admin";
}

It surely works in ready.php. (Maybe you'd have to alter the syntax a bit... wire instead of this)

Just tried this inside one of my modules, and it works as expected:

    public function init() {
        parent::init();
        if ($this->page->template == 'admin') {
            $this->wire->message("in admin");
        } else {
            $this->wire->message("not in admin");
        }
    }

 

Edited by dragan
added module example code
  • Like 2

Share this post


Link to post
Share on other sites

@Noel Boss

I'm using this code in hooks to Templatefile::render and didn't have any issues with it. 

	if (strpos($_SERVER['REQUEST_URI'], $this->wire('config')->urls->admin) === 0 || $this->wire('page')->template->name == 'admin') return;

 

  • Like 2

Share this post


Link to post
Share on other sites

Thanks four your suggestions… However, I'm talking about the init() method inside a module, not ready and not render (for render, the page needs to be there, so ready is already fired) – this is early in the boot process, no page and no template is available at that stage… sometimes not even a process… (at least wherever I tested it) – also parent::init throws an error.I am also not talking about the init.php – this might be different…

4 hours ago, dragan said:

Doesn't this work?

Nope 😉 

2115815220_Screenshot2019-09-29at18_30_08.png.ca4999d379d12ea053ffe88c44de71b8.png

 

@Zeka – thats about what I do with the first and the last test from my example, but it feels very much like a hack for my taste…

I currently use a Hook to extend wire that looks the following:

public function __construct() {
		$this->addHookMethod('Wire::isAdmin', $this, 'isAdminHook');
}


public function isAdminHook(HookEvent $event) {
		$event->return = false;

		if (
			$this->process instanceof ProcessPageList // Admin Page List
			|| $this->process instanceof ProcessPageEdit // Edit Screen
			|| strpos($this->input->url, $this->urls->admin) !== false // determine from Admin url…
			|| ($event->arguments(0) instanceof Page && $event->arguments(0)->rootParent->id == $this->config->adminRootPageID) // if a page is passed…
		) {
			$event->return = true;
		}
}

 

Share this post


Link to post
Share on other sites

Hi @Noel Boss, - I haven't understand why you need init() and why you are not able to use ready(). (Maybe, because you haven't told 😉

But what about testing with prioritizing your hook(s)? Maybe with init() it may run lately, or in ready() (as one of the early birds), will do what you are after??

Links:

https://processwire.com/docs/modules/hooks/#hook-priority

and

 

Share this post


Link to post
Share on other sites

@horst – I need init to bind hooks that can only be bound before ready fires – for example render, or viewable … Therefore, hook priorities don’t help me. I could just bind the hooks anyway, but I only want to bind the hooks, when I really need them… My goal is to not bloat the system with hooks … I use tons of them, but I only wan’t to invoke them wenn really needed.

For example. some of the hooks are access related and since PW does not provide a robust and native way to hook into page access features [viewable about the only option, or filtering find queries, both not great options but it's what you get…] I have to be very early in to boot process, sometimes earlier than init ( __construct() ) … These hooks are costly since I have to check for all pages with related pages and then get a blacklist from ID’s that I can then later use filter my results so I don’t get wrong page counts when requesting pages…

@ryan it would really be great to be able to hook into the access system on a lower api level… (not directly on sql…) you’ve built some nice modules, but they all are on top of the current system and don’t work for find queries…

Share this post


Link to post
Share on other sites
2 hours ago, Noel Boss said:

 @ryan it would really be great to be able to hook into the access system on a lower api level… (not directly on sql…) you’ve built some nice modules, but they all are on top of the current system and don’t work for find queries…

That's not really true. Ryan's Dynamic Roles module does add additional sql clauses to ensure dynamic roles are fully resolved at the database level. Sadly is the module is not very well maintained and it could also be build a bit more flexible (e.g. matching on calculated values instead of just "membership"), but it is possible.

2 hours ago, Noel Boss said:

For example. some of the hooks are access related and since PW does not provide a robust and native way to hook into page access features [viewable about the only option, or filtering find queries, both not great options but it's what you get…] I have to be very early in to boot process, sometimes earlier than init ( __construct() ) … These hooks are costly since I have to check for all pages with related pages and then get a blacklist from ID’s that I can then later use filter my results so I don’t get wrong page counts when requesting pages…

This to me sounds like a very hacky workaround. You initially said you don't want to bloat the system with hooks. Blacklisting IDs and filtering them at runtime is very likely to be way worse for performance than a handful or two more hooks.

Share this post


Link to post
Share on other sites

Hi @LostKobrakai – we are diverting from the subject 😉

My business logic is a bit complicated. I have many organisations, and an organisation have different memberships and depending on these memberships, the users assigned to the organusation can view different pages … and the users themselves have different roles inside the organisation and some pages are blocked or unlocked based on the role in the organisation. I could not find any module or core functionality that let me handle this use case with elegance. So what I do is i get all the pages blocked by a specific selector based on language, membership and role (and sometimes login state etc.) and cache the resulting ids based on these attributes [so they are only fetched once per membership-role combo-language until a page matching relevant template or the user or the organisation changes … complicated eh 😉], this needs to happen very early so I don't miss any query operations later on. I then filter using a hook by appending the id's as a id!=1|2|3 selector … thats the most efficient way I found. – I tried most of the modules out there, not sure if I found this one you mentioned @LostKobrakai – I'll have a look at it, thanks!

Also, I just recently found the ___getQueryAllowedTemplatesWhere() hook in PageFinder.php … I might investigate this one a bit more… (thats the one Dynamic Roles uses as well)

So, back to the topic, I use hooks here, and elsewhere for other purposes inside the init() method and it would be nice to have a consistent and simple way to check if we are in admin or not 🙂

Share this post


Link to post
Share on other sites
2 hours ago, Noel Boss said:

So, back to the topic, I use hooks here, and elsewhere for other purposes inside the init() method and it would be nice to have a consistent and simple way to check if we are in admin or not

I guess this is a bit of a chicken and egg problem. The admin in processwire is hardly anything special based on what the core knows about it. It's a bunch of pages, which just happens to be tightly access controlled and forwarding their handling to process modules instead of rendering templates. So before knowing the page you're on there's not really a good way to know if the request is going to serve an "admin page" or not. To query the current page a lot of things already need to be started, and I guess you want to hook into those before any pages are queried, at best by already knowing the context, which is not going to work.

A good example is the function you've shown in your initial post. It's a good heuristic for determining if the user is in the admin, but also not bullet prove, as there can be normal pages as children of $this->config->adminRootPageID as well. It might rarely happen, but it's possible. The only way to be sure is actually having $page queried.

  • 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 sambadave
      Hi there
      Short version of question
      Let's say I have a page in the admin that contains a field... Is it possible to output the content from that field on another page in the admin? Almost like a reference.
      Longer version of question (with example)
      A house builder with multiple (60+) developments. They want to be able to create notices/messages that can be added to one or many developments. Handy for things like regional covid lockdowns or temporary office closures due to bad weather.
      My approach for the admin editing options:
      Add each message to each development
      Pros: You edit the message on the development page in context
      Cons: Very time consuming and repetitive if the same message needs to be applied to 60+ developments
        Control all the messages from one admin page and say which development each message should be applied to
      Pros: Easier to add/remove messages to more than one development at a time. Control all messages from one place.
      Cons: Content is not added on development page, which is where typical admin users may expect to find it I went for option 2 due to flexibility, and created a page within the admin for global development notices. This contains a repeater with:
      Field for message to display Checkbox list of all developments. The user can select which ones to apply each message to It's working really well but the only thing is that if the user goes to a specific development in the admin, the relevant messages aren't displayed in context (as they aren't edited on that page and instead on the global development notices page)... which may cause confusion when a new staff member / content admin tries to edit the text but there is no field when they go to the development admin page where they expect to see it...
      Solution???
      I don't require the message(s) to also be editable on the development page, but I wondered if there was a nice way to show it/them somehow. I feel like I am missing something really simple as I'm sure ProcessWire will have a nice way of achieving this, or maybe there are field settings that allow this kind of thing to happen?
      Any ideas on approaches or similar experiences would be much appreciated, even if it is just a much simpler example with the content from one field being shown on another admin page to get the ball rolling.
      Thanks in advance for any advice :)
    • By CachePuzzles
      Hi there,
      I'm probably missing something simple, but I'm just setting up my first site so I guess that's bound to happen.
      I've installed the LoginRegistration module and at first I was thinking that the confirmation emails weren't being sent. However I now see that new user confirmation emails are taking 20+ minutes to arrive. Is there a way to speed this up?
      Also the email is coming from processwire@mydomain - I couldn't found a place to change this.
      Any advice or help would be great!
      Brian
    • By rjgamer
      Hi,
      is there a hook after the current (active) page got created? Or which method got called in the Page class after the Constructor of the current page got initialized?
      Thanks.
       
    • By Kiwi Chris
      I need to restrict editing access based on both the user role, and the value of a sub-field in a page reference field.
      eg $page->competition->closingDate 
      There's some discussion about restricting editing access based on role, and that works, but when I try to access the page via the method @Robin S suggests, the page returned is an admin page rather than the page being edited, so I don't have access to the edited page's fields.
       
    • By humanafterall
      Hi,
      I would like to set an admin template to 'https only' as recommended in the Processwire security docs.
      However if I do this it forces this setting locally too, resulting in https://localhost requests which result in an error page.
      Is there a simple way round this? Setting https for templates in the config?
      Thanks!
×
×
  • Create New...