Jump to content

Custom PHP code selector


blynx
 Share

Recommended Posts

Hej,

i am trying to build a custom PHP code selector to get all pages using a user template for a site using multiple templates for users.

Here are my two non-working approaches:

/**
 * A
 */
return function() {
$template_ids = implode("|", $config->userTemplateIDs);
return $pages->find("template=$template_ids, include=all");
};


/**
 * B
 */
return $pages->find("template=".implode("|", $config->userTemplateIDs).", include=all");

Maybe I am thinking too complicated and I miss something here - basically I need a Page Field which can select from all users with all the different user templates ...
uhm - has anyone an idea how this might work?

Also in general - has anyone an idea what is actually possible with this custom php code selector? I guess it is somewhat restrained?

Thanks!
Steffen

EDIT:

I guess that I can't access $config?

Link to comment
Share on other sites

Yes!

Thanks @LostKobrakai, thats it - should've tried that one too ...
@Martijn Geerts, yep - I also tried wire('config') but that didn't work either – and I was not sure about `template=` vs. `template.id=`, too ... both work though ;)

PS:

Is there actually some kind of summarized documentation of where which variables are scoped and why? Like to get to know some underlying concepts of processwire? Or a forums thread where things like that are explained more thoroughly?

  • Like 1
Link to comment
Share on other sites

There are basically four different environments to talk about.

  1. TemplateFile
    TemplateFile is core class, which does include your template files, but does also power things like $page->render(), wireRenderFile(), wireIncludeFile() and others. This class will automatically make all API Variables available as local variables. Meaning all those included files can directly use $pages, $page, … . It won't work inside any functions defined in those files, because of the way PHP does scope variables.
  2. Classes extending Wire
    Every class, which is extending the Wire class will have access to API variables via $this->pages, $this->page, if the properties or __get() are not overwritten. Also there's $this->wire('pages'), which is less likely to be overwritten (even some core classes need to use $this->wire()).
  3. Anonymous functions
    There are some methods in the processwire code, which accept anonymous functions as parameters (e.g. WireCache). Those anonymous functions can retrieve api variables as parameters, even though I'm not sure how exactly this is working or if that's often used.
  4. Everywhere else
    Outside of wire classes, template files and special anonymous functions there's the wire() function, which is basically the same as $this->wire() in wire classes, but as a global function, which is accessable anywhere after pw is started.
    With PW 3.0 and multi-instance this is the option to avoid.

Places, which technically are number 2, but it may not be apparent to everybody:

Custom PHP code for fields like FieldtypePage or FieldtypeMarkup:
As those PHP code is evaluated/run inside those (input)field classes there's (besides manually available local api variables) always the option to use $this->pages or $this->wire('pages').

All those template files included by the TemplateFile class:
For the same reason as above there's not only $pages available in those template files, but also $this->pages, $this->wire('pages').

  • Like 10
Link to comment
Share on other sites

On 11. August 2016 at 8:47 PM, LostKobrakai said:

Everywhere else
[...]

With PW 3.0 and multi-instance this is the option to avoid.

Great overview, Benjamin!

Have you any reference on this or could you explain why we should avoid wire(). What's the best way to go, using $this?

Link to comment
Share on other sites

It's because all other options are aware of their instance (e.g. a page of instance1 will get the configs of instance1), whereas the global wire function does not have state and therefore does only ever return the "primary" instance, which is simply the first one ever instantiated.

Edit: Maybe 'avoid' it to hard, but one needs to be aware that the function is not aware of additional instances. Especially in hooks or alike, where people are currently often using wire() one should rather use $event->wire() so the hook is not prone to using a different instance than intended.

  • Like 4
Link to comment
Share on other sites

29 minutes ago, LostKobrakai said:

It's because all other options are aware of their instance (e.g. a page of instance1 will get the configs of instance1), whereas the global wire function does not have state and therefore does only ever return the "primary" instance, which is simply the first one ever instantiated.

Thanks for the explanations. Is there an instance-aware way to get API variables in function scope?

Link to comment
Share on other sites

There isn't one, other than passing the instance into the function as parameter. But really a class is way better in handling this kind of state. 

<?php namespace ProcessWire;

class Helpers extends Wire{
	
	public function getGlobalSeo()
	{
		return $this->wire('pages')->get('/')->seo;
	}
}

In the init.php

$helpers = $this->wire(new Helpers); // Wire the instance into the helpers class
$this->wire('helpers', $helpers); // Add as api variable

In your templates

$seo = $helpers->getGlobalSeo();

 

  • Like 4
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.

  • Similar Content

    • By Robin S
      Lister Selector
      A Process module that uses Lister/ListerPro, but with a selector string input instead of the normal InputfieldSelector filters.
      Features
      For power users, typing a selector string is often faster and more intuitive than fiddling with InputfieldSelector. It also lets you copy/paste selector strings that you might be using somewhere else in your code.
      Allows the Lister rows to be sorted by multiple fields (not possible in Lister/ListerPro)
      Allows the use of OR-groups (not possible in Lister/ListerPro)
      If ListerPro is installed you can run ListerPro actions on the listed pages - the available actions are defined in the module config.
      Bookmarks can be configured in the module config and accessed via the flyout menu for the module page. For your convenience you can copy/paste a bookmark string from the note at the bottom of the Lister Selector results.
      Usage
      Type your selector string on the Selector tab. The selector is applied when the "Selector string" field is blurred, so hit Tab when you have finished typing your selector.
      Unlike Lister/ListerPro, you can't sort results by clicking the column headings. Control the sort within the selector string instead.
      Superusers can jump to the module config (e.g. to create a bookmark) by clicking the cog icon at the top right of the module interface.
      The module is mostly intended for use by superusers, because in most cases site editors won't understand the ProcessWire selector string syntax. If you want another role to be able to access Lister Selector then give the role the "lister-selector" permission. Only superusers can define bookmarks because in ProcessWire module config screens are only accessible to superusers.
      Screenshots
      Process page

      Module config (when ListerPro is installed)

      Advanced
      If for any reason you want to create dynamic bookmark links to Lister Selector for a given selector you can do that like this:
      /** @var $pls ProcessListerSelector */ $pls = $modules->get('ProcessListerSelector'); // Define selector $selector = "template=foo, title%=bar"; // Define columns (optional) $columns = 'title,modified'; $pls_link = $pls->getProcessPage()->url . '?bm=' . $pls->urlSafeBase64Encode($selector . ':' . $columns); echo "<a href='$pls_link'>My link</a>";  
      https://github.com/Toutouwai/ProcessListerSelector
      https://modules.processwire.com/modules/process-lister-selector/
    • By Peter Knight
      Hey I'm building my first new site in well over a year and am a little rusty on selectors but particularly retrieving sub-fields of selected pages.
      I am trying to output the meta data of a blog post as follows.
      [Person Name] is just a field with a Page Reference and simple enough.
      [Job Title] is the sub-field within the page that was referenced above.
      I actually have it working with the following:
      Posted by: <?php if($page->insight_author) { echo $page->insight_author("<a href='{url}'>{title}</a>");} ?> , <?php $roles = $page->insight_author; foreach ($roles as $role) { echo "{$role->staff_role}";} ?> but was wondering how to do this with selector sub-selectors instead. My current code is probably quite 'old school'?
      Thanks
       
    • By theoretic
      Hi there! And thanks for Processwire!
      I have an interesting task which i cannot fulfill as i want. Maybe someone could help me please?
      Let's imagine a simple page structure of this kind:
      Category 1
      + Item 1.1
      + Item 1.2
      Category 2
      + Item 2.1
      + Item 2.2
      My task is to attach some items to more than one category, at least to show some items on different frontend category pages. With PW, it's a piece of cake. I've just created a field called Items (of type Page Reference) and attrached it to Category template. Since i have lots of items inside each category i preferred to use Page Autocomplete input for my Items field. The pages available for autocomplete are restricted by a very simple selector:
      template=item
      It works like a charm. But later i decided to make this autocomplete even smarter and to exclude current category children items from it. I tried to update my selector this way...
      template=item,parent!=(page)
      ...and oops, this broke my selector. My autocomplete founds nothing. Sorry, i had to replace the square braces by () because of this forum limitations, i swear i'm using square brackets in real-life selector!
      What am i doing wrong? And is there any way to include current page info in autocomplete-related selectors? Thanks in advance!
       
    • By ottogal
      Hello all,
      using PW 3.0.148 with the regular site profile for a blog, I got an an empty pagination output when I had a Toggle field in the selector.
      The Toggle Fieldtype was introduced with https://processwire.com/blog/posts/pw-3.0.139/ .
      The selector resulting in empty pagination:
      $posts = $pages->find("parent=blog, sort=-date, limit=10, toggle_field=0"); It worked well, when I replaced the Toggle field with a Checkbox field:
      $posts = $pages->find("parent=blog, sort=-date, limit=10, checkbox_field=0"); So the prerequisites for the pagination to work are given.
      The settings for the Toggle field were:
      Formatted value: Integer Label Type: Yes/No Input Type: Toggle buttons Default selected option: No Thanks for any hints!
    • By snck
      Hi there,
      I have a problem constructing a selector that finds all pages that refer to pages with a specific template.
      I have pages using an event template and I want to show events based on a specific context. In this example I want to filter the results and only show event pages that relate to a specific template (exhibitions) in their page field related_pages.
      What I tried:
      $events = $pages->find("template=event, related_pages.template.name=exhibition"); Unfortunately it does not work (0 results).
      Same with this:
      $events = $pages->find("template=event, related_pages=[template.name=exhibition]"); At the moment I am helping myself with the following lines, but I have a strong feeling that there is a more efficient solution:
      $events = $pages->find("template=event"); foreach($events as $event){ if(!count($event->related_pages->find("template=exhibition"))){ $events->remove($event); } }  
      I really hope that one of you can help me out.
      Thanks in advance!
      Flo
×
×
  • Create New...