Issue with public_navigation_main filter

Hi.

It seems I’ve got an issue with the public_navigation_main filter: I’m using the Reference plugin, and wanted to change the navigation menu item from “References” to “Item Types” when no other metadata element was selected in the plugin configuration.

I’ve changed the code, that is now checking whether only Item Types are selected, and in that case passes to the public_navigation_main filter the new label, instead of the original one.

I would expect that label to be used, but instead the original one is shown, as it it the one associated with that menu item in the admin/appearance/edit-navigation page (the theme is Thanks, Roy).

Is there a way to programmatically override the original label?

Thanks.

Because its editable with the form, public_navigation_main basically serves as input to the navigation form. Once an entry is saved in the form, the label input there overrides whatever the filter provides as a default. So, if the page is already saved in the navigation, you can’t use the filter to change the label.

So, the only solution would be to create another entry for the Item Types? Or could I intervene on the saved option, changing its name when it gets retrieved, or even in the db table itself?

(Incidentally: it comes to my mind now that this difficulty at changing the labels creates another issue when trying to build a multilanguage repository, as the navigation menu is stuck to the entries saved in the form; only option to make it work seems to be to leave the original English label).

I’ve found a solution, it works despite not being particularly elegant: I’m rewriting the option saved in the db every time the navigation menu is shown, unless the correct label is already there (I’m giving for granted there aren’t many continuous changes).

public function hookPublicHead($args)
{
[...]
$option_old = get_option('public_navigation_main');
$pattern = '/(.*{"uid":"..reference"[^}]*,"label":")([^"]*)(".*)/';
$replacement = '$1' . $label . '$3';
$option_new = preg_replace($pattern, $replacement, $option_old);
if ($option_old != $option_new) set_option('public_navigation_main', $option_new);
}

@jflatnes, would you say there is a better way of getting to the same result?

If the logic for which is the correct label can only change when the plugin settings are changed, perhaps it’s simpler to just check for this and make your change in the plugin’s configuration callback?

I probably wouldn’t use a regular expression here either to do the replacement, instead parsing the option, making the change, and re-serializing it.

It seems to me that we could add an additional filter for public nav that lets you modify the “after” state of the navigation, just before it’s displayed… but it would always work somewhat differently from the other nav filters: the public nav uses a Navigation object at this point, not just an array of links like the others do. So it’s a little tricky.

Hmm, the idea is that, if in the plugin there are only Item Types selected, and not any other metadata (or, the opposite), the plugin will change all labels accordingly (so, “Item Types” for the nav menu, “Browse by Item Type”, etc.). So, your idea is actually quite good, it would reduce the amount of times the Options table is checked. I’ll give it a try.

I do not know how to parse and re-serialize; could you point me to some code or explanation, please?

Thanks.

This option is stored as JSON, so you can use json_decode($option, true) to turn it into a PHP array, modify the array, and then use json_encode to turn that array back into the JSON-formatted text to save back to the option.

Thanks for the tips, John.
I’ve changed the function dropping the Regular Expression; it’s now

$navItems = json_decode(get_option('public_navigation_main'), true) ?: array();
foreach ($navItems AS $key=>$navItem) {
	if ($navItem['uid'] == '/references') {
		if ($navItem['label'] != $label) {
			$navItems[$key]['label'] = $label;
			$optionValue = json_encode($navItems);
			set_option('public_navigation_main', $optionValue);
			return true;
		}
	}
}

As for the other tip, I’ve moved the change to the plugin’s configuration callback; it surely makes more sense.
Cheers.