Jump to content

Get all pages that have certain field buried inside other fields in them


arturogsz
 Share

Recommended Posts

Hi everyone.

I have a field buried inside other fields on several pages. It is a page reference field I use for setting navigation links (navbar, footer, banners, etc.). I need to get the pages that ultimately "contain" this field. This is, the pages the user edit in the admin and from where they set its value. These pages can be anywhere in the pages tree.

These are two examples of pages and their fields structures:

footer (Page) -> footer_columns (Repeater) -> nav_items (Repeater) -> nav_item (FieldSetPage) -> page_selector (Page Reference)

home (Page) -> home_covers (Repeater) -> nav_item (FieldSetPage) -> page_selector (Page Reference)

I need to get the ids of all pages that "contain" the page_selector field buried in their fields "trees". Since the pages that can contain it are not of the same template and will be changing (any page can start using it), I am not sure it can be solved using the pages API find function. I have tried examining the DB directly (I have no problem with MySQL) but haven't been able to decipher the relations between fields, repeaters and pages.

Any help will be appreciated

Link to comment
Share on other sites

Hi, welcome to the ProcessWire forums! I’m not sure I fully grokked you requirements, but I made you this monstrosity:

function getTemplatesFromField(Field $field, array &$templates) {
    foreach ($field->getTemplates() as $tpl) {
        $fieldUsingThis = fields()->get('type=FieldtypeFieldsetPage|FieldtypeRepeater, template_id=' . $tpl->id);

        if ($fieldUsingThis->id) {
            getTemplatesFromField($fieldUsingThis, $templates);
        } else {
            $templates[] = $tpl;
        }
    }
}

$templates = [];
getTemplatesFromField(fields()->get('nav_item'), $templates);
var_dump($templates);

That should print out all templates that contain the field “nav_item” inside their own fieldgroups or nested anywhere inside their FieldsetPage and Repeater fields.

You could probably make something similar in SQL with an iterative CTE, but it’s going to be a bit of a pain because some of the data is stored in JSON columns and it’s hard to get from a repeater/fieldsetpage template to its field… Doing it in PHP should be fast enough, because all this info is loaded by ProcessWire anyway.

  • Like 1
Link to comment
Share on other sites

Another possible way to approach it is to find both normal and repeater pages and then convert the repeater pages into the non-repeater pages that contain them. FieldsetPage is a kind of Repeater.

// Function to get the root container page when the supplied page might be a RepeaterPage
function getRootContainer($page) {
	if($page instanceof RepeaterPage) {
		return getRootContainer($page->getForPage());
	} else {
		return $page;
	}
}

// Get your Page Reference field
$f = $fields->get('page_selector');
// Get the templates that contain the field (including Repeater templates)
$tpls = $f->getTemplates();
// Implode to a string for use in a selector
$tpls_string = $tpls->implode('|', 'name');
// Find pages (including Repeater pages) where the field is populated
// The check_access=0 is so that Repeater pages are found when $user is a non-superuser
$items = $pages->find("template=$tpls_string, check_access=0, $f.count>0");
// An empty PageArray that will hold the results
$results = new PageArray();
foreach($items as $item) {
	// Convert any Repeater pages to their root container page and add to the results
	$results->add(getRootContainer($item));
}
// Now use $results as needed

 

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