Jump to content

Situation where I need set a value for a page selected from a pagefield


Gabe
 Share

Recommended Posts

Hi, I'm fairly new to PW, but have learned a lot from this forum and working with PW over the last few weeks.  I've run into what seems to be a simple problem, but can't seem to find a workable solution.  Sorry if the title isn't very descriptive, I'm not sure how to describe this problem.  

I'm working on a site for a company that manufactures and installs countertops.  They have various materials available for countertops.  Each one of the materials is a page like this:

Materials
-- Granite
-- Quartz
-- Laminate

On each of the material pages there are various fields for descriptions, sink-mount options (page field), etc...  All of that works great and it makes it very easy for the client to add or remove materials in the future.

Here is where the problem comes in.  In addition to the description and sink-mount fields, each material needs to have a set of fields to describe its characteristics and that set of fields must be the same for each material.  These would be things like Durability, Ease of Maintenance,  Chip Resistance, Repairability, etc...  Each characteristic would have a value of 1 - 100.

Of course, my first thought is to just create these fields and add them to the appropriate template.  However, the client would like to be able to add/remove/edit characteristics just like they can with materials, so pages seem like the ideal solution.  

But then... how do I make those all of those characteristic pages show up on the materials pages AND allow a value to be set for them...  That doesn't seem to be possible.  I've tried to think through every possible solution - repeater field, page table, repeater field with a page field, repeater field with a page table.  Nothing seems to solve this problem.

I feel like there is probably is really simple solution I'm overlooking or I've approached this in completely the wrong way.  

Thanks for any suggestions!

 

Link to comment
Share on other sites

If I get you right, you need to have a page field where the user can add/remove characteristics and at the same time the user should be able to enter a value for that characteristic.

I'm not sure how you could implement this with available PW functionality at the moment, but there is a discussion that seems to be related to your use case: https://processwire.com/talk/topic/7902-ability-to-edit-pages-from-a-page-field/?hl=%2Bpages+%2Bfield+%2Badd+%2Bpages+%2Bapi

And also maybe the Profield Page Table may help.

  • Like 1
Link to comment
Share on other sites

And also maybe the Profield Page Table may help.

Keep in mind that the link gebeer added here is to Profields Table, which is very different to Profields Page Table. Also, note that the latter is in the core of PW 2.5, just not installed by default.

  • Like 1
Link to comment
Share on other sites

Thanks gebeer, onjegolders & adrian.  I've tried using the PageTable field.  Initially I thought that would work, but that adds pages and that's not really what I need to do.  I already have the pages I need.  I just need to be able to assign a value to them when they are selected from a pagefield on a different page.  I guess I'm not really using the pages as a 'page', but as a way to display a set of options on several other pages via a pagefield.  If one of those options (pages) is selected, then a value needs to be set for it.   Hope that makes sense.

@gebeer - the discussion you linked to does seems related.  I'll try to contribute to that.

Link to comment
Share on other sites

If you want to have the settings on one page trigger some other change in some other page then generally you need a hook, probably in an autoload module that will listen to your pages where the initial change is occurring (basically an 'event') and then dynamically/automatically effect changes in a different page(s). I am not all that with hooks (yet) but others here should be able to guide you :-).

Maybe describe your situation further, e.g. a step-by-step sequence of events as well as exactly what needs changing, e.g. fields need to be populated, pages need to be published, etc...Hope this makes sense :-)

Link to comment
Share on other sites

Thanks kongondo,

To clarify, if the user selected the 'Towing Capacity' pagefield option for 'Car A', the value set would be for that page (Car A).  If they were editing 'Car B' and selected the 'Towing Capacity' option, the value they set would be for 'Car B'.  Hope that makes sense....

I've worked with dependencies a bit, but I'm certainly no expert in them.  What I would like to do would look exactly like what is being done with the 'Villa Toggles'  at 1:06 in the video (http://youtu.be/hqLs9YNYKMM?t=1m6s).   However, the options (Villa Toggles) would be a pagefield and the individual options (Air Conditioning, Beachfront, Children Welcome, etc.) would be pages.  Problem is, each time the end user adds or removes an option (page), I would have to manually create/remove a field to hold the value for that option and create/remove the dependency.    Maybe I'm over-thinking this and giving the end user too much control  :-) 

(for reference, my other post kongondo mentioned is https://processwire.com/talk/topic/7892-situation-where-i-need-set-a-value-for-a-page-selected-from-a-pagefield/ )

Gabe,

If you cannot have those options 'pre-installed' and want to create fields on the fly then you would also need an autoload module of some sort, I think. But I am not sure adding fields that way is the way to go. Maybe something to hook into Page Table field...hmmm...Let's hear what others think :D

Link to comment
Share on other sites

I think autoloads and hooks might be getting a bit over my head at the moment.  I have a lot more to learn about PW.   

I might have to stick with static fields for the moment and have the client contact me to change them as needed.  

If anyone else has any suggestions though, I'd be happy to give them a try!

Link to comment
Share on other sites

Thanks, I'm definitely willing (and excited) to learn!

Hello Gabe and welcome,

Are we talking about a one single template called material here? Are all of the characteristics usually defined for all of the materials? And the problem is that you don't want to give your client access to the templates and fields of the system?

If the answer to all questions is 'yes', then I think approaching the problem with autoloading modules, hooks, PageTables etc is a bit overkill. It is amazingly simple to create a Process-module that you can give the client access to, which simply allows the client to add/edit/remove such fields on the material-template. Here are all the relevant API-methods

$template = wire('templates')->get('material');

// Adding a field 

$field = new Field();
$field->name  = "c_durability";
$field->label = "Durability";
$field->type  = "Integer";
$field->save();

$template->fields->add($field);
$template->save('fields');

// Updating the label

$field = wire('fields')->get('c_durability');
$field->label = "Characteristics: Durability";
$field->save();

// Removing the field

$field = wire('fields')->get('c_durability');
$fieldGroups = $field->getFieldgroups();
if($fieldGroups->count() > 0)
{
  foreach($fieldGroups as $fieldGroup)
  {
    $fieldGroup->remove($field);
    $fieldGroup->save();
  }
}
wire('fields')->delete($field);

Now of course you still need an UI with some confirmation dialogs and validation, but I'm sure you get the idea (if not, ask away).

If you really, really want to create a module that does this automatically based on pages, then yes, that can be done with the same methods as well. Such module could be something like this

class PageFieldCreator extends WireData implements Module
{
  protected $material_template = "material";
  protected $char_template = "characteristic";
  protected $template;

  public static function getModuleInfo()
  {
    return Array(
      'title'    => __('Page Field Creator', __FILE__),
      'summary'  => __('Demo-module that creates fields from pages'),
      'version'  => 1,
      'singular' => true,
      'autoload' => true,
    );
  }

  public function init()
  {
    $this->addHookAfter('Pages::saved', $this, 'saveHook');
  }

  public function saveHook(HookEvent $e)
  {
    $page = $e->argument(0);
    if($page->template->name != $this->char_template)
      return;

    if($page->parent->isTrash())
      $this->handleDelete($page);
    else
      $this->handleSave($page);
  }

  protected function handleDelete(Page $page)
  {
    $fieldname = $this->getFieldname($page);
    $field = $this->fields->get($fieldname);
    if(!$field)
      return;
    $fieldGroups = $field->getFieldgroups();
    if($fieldGroups->count() > 0)
    {
      foreach($fieldGroups as $fieldGroup)
      {
        $fieldGroup->remove($field);
        $fieldGroup->save();
      }
    }
    $this->fields->delete($field);
    $this->message(__("Characteristic {$fieldname} deleted"));
  }

  protected function handleSave(Page $page)
  {
    $fieldname = $this->getFieldname($page);
    $field = $this->fields->get($fieldname);
    if(!$field)
       $this->handleNew($page);
    else
       $this->handleUpdate($field,$page);
  }

  protected function handleUpdate(Field $field, Page $page)
  {
    if(strcmp($field->label, $page->title) == 0)
      return;
    $field->label = $page->title;
    $field->save();
    $this->message(__("Characteristic {$field->name} updated"));
  }

  protected function handleNew(Page $page)
  {
    $field = new Field();
    $field->name  = $this->getFieldname($page);
    $field->label = $page->title;
    $field->type  = "Integer";
    $field->save();

    $tpl = $this->getTemplate();
    $tpl->fields->add($field);
    $tpl->save('fields');

    $this->message(__("Characteristic {$field->name} created"));
  }

  protected function getFieldname(Page $page)
  {
    return "c_".$this->sanitizer->fieldName($page->name);
  }

  protected function getTemplate()
  {
    if(!isset($this->template))
      $this->template = $this->templates->get($this->material_template);
    return $this->template;   
  }
}

Such module would create/update/delete a field and update the template called material when a page that has the template characteristic is created/updated/trashed. The demo creates the field using the name of the page prefixed with "c_".

While this would technically work, I'd still just create a Process-module for managing them to gain more fine-tuned control. Like I mentioned in the beginning, hooking is also a bit overkill since the fields are rarely modified.

  • Like 10
Link to comment
Share on other sites

Thanks SO much sforsman!  I really appreciate you taking the time to put this together.  The process module definitely is the quick and easy way to get this done.  I'm going to play around with the module though just to get a better grasp on how modules work.

Thanks again to everyone help with this!

  • Like 1
Link to comment
Share on other sites

No problem at all! I'm just glad if it was any help for you.

PS. Just let us know if you need any help with the actual Process-module - I can also write an example of those if you like (since they work slightly different compared to the one I posted). However this is where you should probably start if you are going to experiment yourself: https://github.com/ryancramerdesign/ProcessHello. 

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