Jump to content
DL7

FieldTypeOptions only "in use" values

Recommended Posts

Hi,

I have multiple Options fields on a certain page. On an overview page I like to add a filter, which display`s all the distinct value`s of the optionfield, but only the once that are in use. As an addition I would like to have the amount of times this specific value is in use. So:

Given the following:

1=ABC

2=DEF

3=FOO

4=BAR

I have for examples 5 pages were

Page 1 uses 1

Page 2 uses 1

Page 3 uses 2

Page 4 uses 4

Page 5 uses 4

So on the overviewpage I like to have an overview with (note the 3=FOO is not displayed):

Options:

ABC (1)

DEF (1)

BAR (2)

I know in the API there is a possibility to use $all_options = $field->type->getOptions($field); But I would need the $all_inuse_options ;-)

Next to that It would be a nice to have to add the count.

Share this post


Link to post
Share on other sites

Hi @Zeka,

Thanks for your swift reply. As I understand ir correctly I would need to create then a page for each individual value. That would work for instance for 10 values, but lets assume the options are countries, is would be a lot of work to add every single country as page.

Explaining it a bit more: What I`m trying to recreate is sort of a very small version of a so called facatted search functionality like on the sidebar on this page: https://www.laptopshop.nl/category/45702/laptops.html

 

Share this post


Link to post
Share on other sites
1 hour ago, DL7 said:

but lets assume the options are countries, is would be a lot of work to add every single country as page.

Migrator has a country list complete with ISO country code fields etc.

58c02369315c3_ScreenShot2017-03-08at7_28_56AM.thumb.png.1a1185c56b1d1c0e7f4e40a95f6fc3da.png

If you want to go this route, install this commit of Migrator: https://github.com/adrianbj/ProcessMigrator/tree/3e2121b8fdb68e9d9dc0c6aca8aae75e923a2669

Alternatively, use https://processwire.com/talk/topic/4523-page-field-select-creator/ and paste in a list of countries, or even http://modules.processwire.com/modules/batch-child-editor/

A CSV list like this (https://developers.google.com/public-data/docs/canonical/countries_csv) would be helpful for the last two options.

  • Like 2

Share this post


Link to post
Share on other sites

Hi @adrian ,

Thanks for this. Very helpful. But i`m still struggeling with the fact on how to get a list of the relevant items.

As per my example above, how would I check first of all the distinct values used? In either approach (options field or page) I still need to "loop" through the $page->category correct? How from an API call can I make sure only distinct values are shown in the loop?

Next to that the trick would also be to add a additional count. I would know how to do this from a SQL perspective, I`m just not sure on how to do this using an API call.

 

Note: a single page will only have 1 value as a set optionvalue (so no multiple values possible on a single page)

Thanks again!

 

Share this post


Link to post
Share on other sites

@DL7

Options ( page with template "options")

- ABS ( page with template "option")
- DEF ( page with template "option")
- BAR ( page with template "option")

Page 1 ( template "page" with single page field "options_field" ) use ABS
Page 2 ( template "page" with single page field "options_field" )  use DEF
Page 3 ( template "page" with single page field "options_field" ) use DEF
Page 4 (template "page" with single page field "options_field" ) use BAR

Then in your output 

$options = $pages->find("template=option, limit=100");

echo $options->each(function($item) {
	$count = $pages->count("template=page, options_filed=$item");
	if($count) {
		return "<li>{$item->title} ({$count})</li>";
	}
});

 

 

  • Like 2

Share this post


Link to post
Share on other sites

You can easily create a select field with countries with FieldtypeSelectExtOption
First install this table countries.sql via MysqlAdmin or another tool. Choose the new table in the settings of your FieldtypeSelectExtOption field. Done!
You have a comfortable access to all the data via API. Read the docs or the related thread https://processwire.com/talk/topic/9320-fieldtype-select-external-option/
 

 

 

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for your help all, I'll give it a try.

Share this post


Link to post
Share on other sites

Again thanks for your help @Zeka. I wasn't aware of the each() function, so that help alot! Just to be clear on the above reactions, with the country list example I just wanted to point out an example of a large dataset. I wasnt looking for a country list itself. But if I need it in the future, I'll have some great pointers on how to upload them ;-)

Next to that if you are really stubborn person (like I am ;-) and still want to utilize the fieldtype options for this, use this code:

$options = $fieldtypes->get('FieldtypeOptions')->getOptions('xyz'); 
$options->each(function($item) {
	$count = wire('pages')->count('template=basic, xyx='.$item.'');
	if($count) {
		echo "<li>{$item->title} ({$count})</li>";
	}
});

 

  • Like 2

Share this post


Link to post
Share on other sites
1 hour ago, DL7 said:

Next to that if you are really stubborn person (like I am ;-) and still want to utilize the fieldtype options for this, use this code:


$options = $fieldtypes->get('FieldtypeOptions')->getOptions('xyz'); 
$options->each(function($item) {
	$count = wire('pages')->count('template=basic, xyx='.$item.'');
	if($count) {
		echo "<li>{$item->title} ({$count})</li>";
	}
});

 

The thing about this approach where you foreach the selectable options (for an Options or a Page field) is that if you have 196 countries (for example) then that is 196 database queries. Not the end of the world or anything but also not very efficient. I like this code from Ryan that requires only a single DB query, and which can be adapted for an Options fieldtype:

$field = $fields->get('my_options_field');
$table = $field->getTable();
$query = $database->query("SELECT data FROM $table");
$ids = $query->fetchAll(PDO::FETCH_COLUMN);
$count_values = array_count_values($ids); // count the frequency of values in the array
arsort($count_values); // sort highest to lowest
// use the option IDs and counts as needed, for example:
$all_options = $field->type->getOptions($field);
echo '<ul>';
foreach($count_values as $option_id => $count) {
    $option = $all_options->get($option_id);
    echo "<li>{$option->title} ({$count})</li>";
}
echo '</ul>';

 

  • Like 1

Share this post


Link to post
Share on other sites

And you are right. In that case I would definitely go for a different approach. The one you mention from ryan is indeed also doing the trick. One thing to mention though on this is that this code isnt taking into account a certain status of the page the Option values it's been used at. I have certain pages that are for instance unpublished, hidden or even have custom status, that i've created myself, those would also be taking into account whereas for the other code I can make that exception on the selector.

 

Share this post


Link to post
Share on other sites
1 hour ago, DL7 said:

One thing to mention though on this is that this code isnt taking into account a certain status of the page the Option values it's been used at.

This is true. It starts to get a little more complex but with a few more steps you can filter out the non-public pages:

$field = $fields->get('my_options_field');
$table = $field->getTable();
$query = $database->query("SELECT data, pages_id FROM $table");
$results = $query->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP); // get multidimensional array of results
$results_page_ids = array_unique(call_user_func_array('array_merge', $results)); // get all the unique page IDs in the results
$public_ids = $pages->find(['id' => $results_page_ids])->explode('id'); // find out which ones are public
$filtered_results = [];
foreach($results as $option_id => $page_ids) {
    // remove any page IDs that are not public
    $filtered_value = array_filter($page_ids, function($value) use ($public_ids) {
        return in_array($value, $public_ids);
    });
    // for each option, count the public pages it is selected on
    if($filtered_value) $filtered_results[$option_id] = count($filtered_value);
}
arsort($filtered_results); // sort highest to lowest
$all_options = $field->type->getOptions($field);
echo '<ul>';
foreach($filtered_results as $option_id => $count) {
    $option = $all_options->get($option_id);
    echo "<li>{$option->title} ({$count})</li>";
}
echo '</ul>';

 

  • Like 2

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 RicknRoller
      In the Doc it says:
      I have an options field (options_colors) configured like this:
      I want to have a query returning only pages with the VALUE 'red'. This is a query that works:
      $newsentries = $pages->find('template=news-entry,options_colors=number1,sort=-created,limit=16'); this is a query which does not work
      $newsentries = $pages->find('template=news-entry,options_colors=red,sort=-created,limit=16'); How do I query for 'red' instead of the title for the value?
    • By rolisx
      Hi Guys,
      Just finished a website locally and wanted to upload it on the webserver of my customer. I got a server 500 error. Now, the guidelines of the hoster (world4you.com) does not allow "Options" in the htaccess-file. So, when I uncomment these:
      Options -Indexes
      Options +FollowSymLinks
      the site is visible, but the content won't show and no links are available. Not sure if I need the Symlinks-part but I guess I need a workaround for the Index-part. Can anybody help here? I need the website up and running asap....
      Thanks!
      Roli
    • By jploch
      Hi! 
      this should be easy, but I can't get it to work.
      I have a repeater with events.
      Every event has an option-field with multiple checkboxes.
      To filter the events on the frontend I have a script, that uses the class names to filter the results (an event can have multiple categories).

      Now I just want to add every checked option (title) to use as my class name.
      This is what I have so far, wich only gets the first title.
      foreach($page->events as $event) { $tags = $event->options->title; echo "<div class='size1of2 {$tags}'>"; echo "<img src='{$event->image->url}'>"; echo "{$event->text_editor}"; echo "</div>"; }
      I know there is an example with a foreach, but how would I use it in this context?
      foreach($page->countries as $country) { echo "<li>$country->title</li>"; }
       
    • By pppws
      hey there,
      i'm using processwire for the first time, so maybe it's a dumb question. but i'm trying to have an options field which values are the users of the processwire. i don't need the values to be displayed, it's just for the administration of the page. but each time a new user is created / a user is deleted the options field should be updated automatically. is something like that possible?
    • By obesegiraffe
      Hi all, first time poster on the forums but long-time user of Processwire. I couldn't find this exact problem in the forums and I'm hoping it's just something simple I'm missing (first day back from vacation so I am a little brain dead). 
      I have a Select Options Field Type where the client can choose an array of numbers. If nothing is chosen, nothing is outputted onto the page. This works for most pages using this specific template. However, on just one page where I have the field set to blank, I am finding it is still outputting "0", when it actually shouldn't be outputting anything. My code:
      <?php if($page->percent_leased->has('id!=0')){ ?> <h2><?=$page->percent_leased->title?>% Leased</h2> <?php } ?> On this specific page, it is outputting "0% Leased". It's also doing something kind of weird in the database under the percent_leased field type. It's repeating the same ID of the specific problem page twice (page ID 1086) when I set it to blank. It works fine if I actually choose a number and the duplicate goes away. I've never really delved deep into the databases so maybe this is normal? 

      The weird thing is is that this is working fine on all other pages using this template. It's just this one page acting weird. FWIW, this particular site is running version 2.6.1. 
      Thanks for reading!
×
×
  • Create New...