hello, this is my first post. I have been working on a website and I am filtering images with tagcloud based on the category. The problem is that I need to load many images on the same page so I tried to use pagination. The problem is that I cant fina a way to paginate after the filtering because I am filtering on the grandparent of the page the image is in. Its a little tricky but here is my code
<?php
$tecnicas = tagcloud($page->children(), array('field'=>'tecnica',
'sort' => 'name',
'sortdir' => 'asc'));
$estilos = tagcloud($page->children(), array('field'=>'estilo',
'sort' => 'name',
'sortdir' => 'asc'));
$rangos_mx = tagcloud($page->children(), array('field'=>'rango_precio_mx',
'sort' => 'name',
'sortdir' => 'asc'));
?>
<div class="obras__filter__navbar">
<form class="obras__filter__list" action="" method="post">
<select name="tecnicas">
<option value="val1">Técnica</option>
<?php foreach($tecnicas as $tecnica): ?>
<option value="<?= $tecnica->name()?>">
<?= $tecnica->name()?>
</option>
<?php endforeach ?>
</select>
<select name="estilos">
<option value="val2">Estilo</option>
<?php foreach($estilos as $estilo): ?>
<option value="<?php echo $estilo->name()?>">
<?= $estilo->name()?>
</option>
<?php endforeach ?>
</select>
<select name="rangos_mx">
<option value="val3">Precio MXN</option>
<?php foreach($rangos_mx as $rango_mx): ?>
<option value="<?php echo $rango_mx->name()?>">
<?= $rango_mx->name()?>
</option>
<?php endforeach ?>
</select>
<div class="obras_btn">
<button type="submit" id="submit" name="submit" value="Submit" class="btn">Filtrar</button>
</div>
</form>
</div>
<?php $autores = $page->children()->paginate(4)?>
<?php var_dump($autores); ?>
<div class="obras__container">
<?php
$items = 0;
foreach($autores as $autor):
?>
<?php
$obras = $autor->children()->flip();
if($_POST){
// 1 FILTRO
if ($_POST['tecnicas'] == 'val1' && $_POST['rangos_mx'] == 'val3') {
$obras = $autor->children()->filterBy('estilo', '*=', $_POST['estilos']); // In here i do
// the filtering of the images.
foreach ($obras as $obra) {
$autores = $obra->parent()->title(); // what I want here is to save all the autors //of each $obra without reapeats
}
$autores = $autores->paginate(4);
var_dump($autores);
}
elseif ($_POST['estilos'] == 'val2' && $_POST['rangos_mx'] == 'val3') {
$obras = $autor->children()->filterBy('tecnica', '*=', $_POST['tecnicas']);
}
elseif ($_POST['tecnicas'] == 'val1' && $_POST['estilos'] == 'val2') {
$obras = $autor->children()->filterBy('rango_precio_mx', '*=', $_POST['rangos_mx']);
}
<?php
$items ++;
endforeach
?>
As I understand it your trying to change the page content based on the selection of a dropdown? I think you would be better off using ajax or a front end solution like list.js. Your current solution looks like it causes a page reload, which is not great from the users point of view. Its late and i cant quite follow your code, but it seems a little overboard.
Are you using a controller at all? If not it might better to move the logic into a controller and do the hard work there with filtering and pagination.
I think it would be useful if you first define what you are trying to do here. There are a lot of if statements in your code that don’t seem to make much sense.
You seem to have a structure like this
– parent page --> autores. --> obras
And you want to show what exactly in the parent page? All obras of all authors if nothing is selected? Filtered obras if something is selected? What needs to be paginated here, the authors or the obras?
@jimbobrjames has already pointed you to the filtering compendium, but your use case seems to be a bit different.
Actually, I think you would better approach this differently.
First get all obras. Then filter if filters are applied.
<?php
$obras = $page->grandchildren()->visible();
Then do the same filtering stuff as described in the filtering compendium
//if filter is set
$obras = $obras->filter(function($child) {
// filter code here
}
I have the main page which has autors as children pages, and each autor has paintings as their children.
Because of the design, I first do a for loop for each autor, and then when I have each autor I do the filtering on each painting of that autor by their tag. The problem is, I am filtering the paintings by tag and gets me a lot of paintings, many of which have the same autors. I need this for filtering the paintings, but the problem is, there are a lot of autors and images to load so I want to paginate. What I am trying yo do is to get the autors that had any paintings after the filtering. I know I should be using a controller but right now I just want to get the logic to work.
Can you tranlsate the dropdown filters for me? What do they mean in english? Are they like types of work, as in oils, sketch, watercolor etc? Why is there three?
Each of that is a tag that each painting page has.
I want to filter by 3 different categories, style, price and technique. Each of those has their options as tags. The filtering I did was to filter by every possible combination of the 3 categories, because I want to be able to filter all the images by say tecnique, or by teccnique and style and so on. I dont know if it makes sense ?
Yes, it makes sense, but you can do this all in one, without all the different if statements. the first value should always. be empty, though. Have a look at the example in the filtering compendium.
the blueprint of each painting is something like this:
fields:
title:
label: Nombre de la obra
type: text
width: 1/2
obra_image:
label: Imagen
type: image
width: 1/2
precio_us:
label: Precio EUA
type: text
width: 1/2
dimensiones:
label: Dimensiones
type: text
width: 1/2
tecnica:
label: Técnica
type: tags
width: 1/2
estilo:
label: Estilo
type: tags
rango_precio_us:
label: Rango de precio USA
type: tags
width: 1/2
<?php
return function($site, $pages, $page) {
$obras = $page->grandchildren();
$tecnicas = tagcloud($page->children(), array(
'field'=>'tecnica',
'sort' => 'name',
'sortdir' => 'asc')
);
$estilos = tagcloud($page->children(), array(
'field'=>'estilo',
'sort' => 'name',
'sortdir' => 'asc')
);
$rangos_mx = tagcloud($page->children(), array(
'field'=>'rango_precio_mx',
'sort' => 'name',
'sortdir' => 'asc')
);
if(r::is('POST') && $data = get()) {
$keys = array('technica', 'estilo', 'rango_price_US');
$obras = $obras->filter(function($child) use($keys, $data) {
// loop through the post request
foreach($data as $key => $value) {
// only act if the value is not empty and the key is valid
if($value && in_array($key, $keys)) {
// return false if the child page's category and value don't match
if(!$match = $child->$key() == $value) {
return false;
}
}
}
// otherwise return the child page
return $child;
});
}
// we apply grouping and pagination here, so that it applies to both the unfiltered and the filtered collections
// lets group the works by author; we use the uid here to make it easy to later find the page again
// then we paginate, so we get 4 groups (= 4 authors and their works) per page.
$groups = $obras->group(function($child) {
return $child->parent()->uid();
})->paginate(4);
// finally, let's create a pagination object for the navigation
$pagination = $groups->pagination();
return [
'groups' => $groups,
'tecnicas' => $tecnicas,
'estilos' => $estilos,
'rangos_mx' => $rangos_mx,
'pagination' => $pagination
];
};
In your template:
<div class="obras__filter__navbar">
<form class="obras__filter__list" action="" method="post">
<select name="tecnicas">
<option value="">Técnica</option>
<?php foreach($tecnicas as $tecnica): ?>
<option value="<?= $tecnica->name()?>">
<?= $tecnica->name()?>
</option>
<?php endforeach ?>
</select>
<select name="estilos">
<option value="">Estilo</option>
<?php foreach($estilos as $estilo): ?>
<option value="<?php echo $estilo->name()?>">
<?= $estilo->name()?>
</option>
<?php endforeach ?>
</select>
<select name="rangos_mx">
<option value="">Precio MXN</option>
<?php foreach($rangos_mx as $rango_mx): ?>
<option value="<?php echo $rango_mx->name()?>">
<?= $rango_mx->name()?>
</option>
<?php endforeach ?>
</select>
<div class="obras_btn">
<button type="submit" id="submit" name="submit" value="Submit" class="btn">Filtrar</button>
</div>
</form>
</div>
<?php
// loops through the groups
foreach($groups as $author => $group):
// find the author page for each work
if($author = $page->children()->findBy('uid', $author)): ?>
<!-- output all the author information your want -->
<h2><?= $author->title() ?></h2>
<?php endif ?>
<!-- loop through the group of works -->
<?php foreach($group as $item): ?>
<!-- output all the information about each work -->
<?= $item->title(); ?>
<!-- and the image etc. -->
<?php endforeach; ?>
<?php endforeach; ?>
The value of the first select option should each be empty.
Thank you for this!
This worked, but I still have a problem, with this code , On the main page I have 6 pages of pagination and if I filter from page 1 say by technique it shows me around 3 pages of pagination. But if I click the second page of the result it shows the second page of all pages. The only way to access the second or third page of a filter result is by making the filtering in the second or third page when all the pictures are. This is the code I have for the pagination nav:
<?php
return function($site, $pages, $page) {
$obras = $page->grandchildren();
$tecnica = tagcloud($page->children(), array(
'field'=>'tecnica',
'sort' => 'name',
'sortdir' => 'asc')
);
$estilo = tagcloud($page->children(), array(
'field'=>'estilo',
'sort' => 'name',
'sortdir' => 'asc')
);
$rango_precio_mx = tagcloud($page->children(), array(
'field'=>'rango_precio_mx',
'sort' => 'name',
'sortdir' => 'asc')
);
if(r::is('POST') && $data = get()) {
$keys = array('tecnica', 'estilo', 'rango_precio_mx');
$obras = $obras->filter(function($child) use($keys, $data) {
// loop through the post request
foreach($data as $key => $value) {
// only act if the value is not empty and the key is valid
if($value && in_array($key, $keys)) {
// return false if the child page's category and value don't match
if(!$match = $child->$key() == $value) {
return false;
}
}
}
// otherwise return the child page
return $child;
});
}
// we apply grouping and pagination here, so that it applies to both the unfiltered and the filtered collections
// lets group the works by author; we use the uid here to make it easy to later find the page again
// then we paginate, so we get 4 groups (= 4 authors and their works) per page.
$groups = $obras->group(function($child) {
return $child->parent()->uid();
})->paginate(5);
// finally, let's create a pagination object for the navigation
$pagination = $groups->pagination();
return [
'groups' => $groups,
'tecnica' => $tecnica,
'estilo' => $estilo,
'rango_precio_mx' => $rango_precio_mx,
'pagination' => $pagination
];
};
In the. controller, we have to add the $data variable:
<?php
return function($site, $pages, $page) {
$obras = $page->grandchildren();
$data = '';
$tecnica = tagcloud($page->children(), array(
'field'=>'tecnica',
'sort' => 'name',
'sortdir' => 'asc')
);
$estilo = tagcloud($page->children(), array(
'field'=>'estilo',
'sort' => 'name',
'sortdir' => 'asc')
);
$rango_precio_mx = tagcloud($page->children(), array(
'field'=>'rango_precio_mx',
'sort' => 'name',
'sortdir' => 'asc')
);
if(r::is('POST') && $data = get()) {
$keys = array('tecnica', 'estilo', 'rango_precio_mx');
$obras = $obras->filter(function($child) use($keys, $data) {
// loop through the post request
foreach($data as $key => $value) {
// only act if the value is not empty and the key is valid
if($value && in_array($key, $keys)) {
// return false if the child page's category and value don't match
if(!$match = $child->$key() == $value) {
return false;
}
}
}
// otherwise return the child page
return $child;
});
}
// we apply grouping and pagination here, so that it applies to both the unfiltered and the filtered collections
// lets group the works by author; we use the uid here to make it easy to later find the page again
// then we paginate, so we get 4 groups (= 4 authors and their works) per page.
$groups = $obras->group(function($child) {
return $child->parent()->uid();
})->paginate(5);
// finally, let's create a pagination object for the navigation
$pagination = $groups->pagination();
return [
'groups' => $groups,
'tecnica' => $tecnica,
'estilo' => $estilo,
'rango_precio_mx' => $rango_precio_mx,
'pagination' => $pagination,
'data' => $data
];
};