But I think it would be necessary to make $context a extended version of $pages with e.g. a ->switch($contextname) method.
I think that the only methods in $pages where context would matter are find() and get(). Those methods are also present on every Page object and can perform the same function as they do in $pages. Except they only find() or get() pages from their family tree (children, grandchildren, and so on). So the page you call find() or get() on already has a root context to everything below it, at least that's the intention. Whereas, the intention with the $pages API var is that it encompasses all contexts (like jQuery's $() method). As a result, I'm not sure I totally understand the value of changing the $pages context as it seems like it's duplicating something we already provide.
On the other hand, what I think could add value is providing contexts that can go outside the tree. And maybe this is what you were trying to say before and I didn't understand at first. But I understand code better than writing, so imagine this:
$context = $pages->context("template=basic-page, modified>=$today");
You could provide any selector as the argument to the context() method. The returned $context would be an instance of PagesType that basically provides you with dedicated get() and find() methods that are confined to the context that was provided in the function call. Meaning, any calls to $context->get() or $context->find() already assume the context that was provided when $context was created. Here's an example:
$news = $pages->context("template=news"); // no pages are loaded from this
$featured = $news->find("featured=1, sort=-date"); // pages are loaded here
While you can already do this (like below), it's not a good idea for big sites for the reason indicated in the code comment:
$news = $pages->find("template=news"); // ALL news pages loaded from this
$featured = $news->find("featured=1, sort=-date"); // already loaded pages are filtered here
For that reason, I think providing the ability to create new $pages-like API vars that can be confined to any selector-specified context does provide real value in being able to create your own API vars... especially for bigger sites. Is this related to what you were already thinking, or have I gone off on a tangent?
Here's how I think you'd use it in a multi language situation:
$languagePages = $pages->context("has_parent=/fr/");
The only thing I can't get past is just that the result of the above would really be no different than just getting the /fr/ page and assigning it to $languagePages:
$languagePages = $pages->get("/fr/");
What's different is that $languagePages would be a dedicated PagesType instance in the first example, and just a Page in the second example. But how you would use them and the syntax for subsequent get() and find() calls would be identical... so I'm not sure this particular approach has much value when one only needs a family context, like /fr/. The value seems to come from when you need to take the context beyond that (whether with languages or anything else).
The context's meta data would-as already mentioned-be stored in fields of the special template of the context's home pages.
I'm not sure I understand about the context's metadata? Can you give an example of the metadata?
BTW: Is there a way to keep template fields from being deleted?
So long as a field is attached to a template, it can't be deleted. Do you mean: is there a way to prevent a field from being removed from a template? If so, there is: you can give the field a 'permanent' flag:
$field->flags = $field->flags | Field::flagPermanent;
You can also make a field non-deleteable by giving it a 'system' flag, so that even if it's not used by any templates, it still can't be deleted:
$field->flags = $field->flags | Field::flagSystem;
If you ever need to remove system or permanent flags, it's intentionally cryptic to remove them (applicable only to system or permanent flags). You can't remove them by just changing the flags or PW will throw an exception. Instead, you have to make your intention clear by first giving it an 'system override' flag:
// removing the system or permanent bits won't work because PW won't allow it
$field->flags = $field->flags & ~Field::flagSystem; // exception gets thrown here
// but if you first give it an override flag, PW will let you do it
$field->flags = $field->flags | Field::flagSystemOverride;
// now you can remove the flags
$field->flags = $field->flags & ~Field::flagSystem;
$field->flags = $field->flags & ~Field::flagPermanent;
$field->flags = $field->flags & ~Field::flagSystemOverride;
This information about adding/removing system flags applies to templates and pages too. Though pages use the term 'status' rather than 'flags'.