ExtensionDesign-Talk

Summary: Talk page for ExtensionDesign.
Maintainer: Petko
Users: (View / Edit)

This space is for User-contributed commentary and notes. Please include your name and a date along with your comment.

Please add new threads on top if possible. --Petko

Calling an extension

It appears an extension is called when:

  • initially as part of PmWiki configuration, but only after it has previously been configured and enabled thru the ExtensionHub
  • for markup or actions enabled by the extension markup ( ... ) {} or $HandleActions []
  • but not when the extension's hub form is submitted to enable the extension

An extension script is like normal recipes, but the hub manages the include_once() line, when the page patterns match what an admin configures in the hub. It is not specifically called or not called, the script is included when the current page matches the page patterns defined in the hub configuration form.

The extension is not "called" "for markup or actions enabled by the extension". When it is included, if the script has Markup() or $HandleActions, they are respected and processed exactly like in classic recipes.

The extension may be included when the hub form is submitted, if SiteAdmin.ExtensionHub matches the defined page patterns. But when the form is submitted, the hub handles the submission, saves the values, and returns to the form with a message "Configuration saved. Return to ExtensionHub". --Petko

Persistent storage

I am having difficulty in understanding where "previously stored values" come from, what they are, and how they updated?
Are "local values saved by an administrator" values those values, and only those values, read from the extension hub's form earlier and saved in the persistent store?
Exactly what does "merging" of the default values do?
Is there any way an extension can use the persistent storage implemented for the ExtensionHub?

simon

After a recipe is enabled in the hub configuration form, the values the admin entered in the form are saved in a text file wiki.d/.extensions/Extensions.Config. This is a hidden directory, make sure your FTP file manager has "show hidden files" enabled.

The hub saves:

  • whether the checkbox Enable configuration is checked
  • the page patterns for this configuration (you can enable a configuration for Main.* or *.RecentChanges), this determines on which pages the current configuration applies and the extension script is included
  • any custom fields provided by the recipe's form page; these were posted at the same time; only if the submitted values are not empty (empty fields are ignored/dropped); these are the "local values saved by an administrator"
    for example, in Filterable you can define custom query selectors for different patterns of pages
  • the stored values are updated when the administrator saves the form again
  • the stored values are removed if the administrator deletes the configuration

When you call extGetConfig(), it returns these values that were saved by the admin in the hub (for the current page, as it matches the page patterns).

Empty fields are not returned, so you want to do array_merge() or SDV() if there are default values. If you call extGetConfig($default_values), it will return the merged local + default values, but you can merge these manually:

$config = extGetConfig(); # get what was saved in the hub
$config = array_merge($default_values, $config); # report any missing values

$config = extGetConfig($default_values); # same result as above

The recipe should use extGetConfig() to get the stored values. At this point I do not recommend to try and use the persistent storage implemented for the ExtensionHub for other values not saved by the hub. --Petko

$conf = extGetConfig ($myDefaultValues)

I need to understand extGetConfig () better. It appears there are three purposes it is used for:

  • reflects the current environment ($conf['=dir'], $conf['=url'])
    and perhaps in the future to influence that environment
  • interface with the extension's hub form (e.g. SiteAdmin/ExtensionHub?action=hub&x=myCoolExtension)
    • return values from the extension's form as entered by the user
    • set values on the extension's form programmatically
    • specify default values for the extension's form sourced variables
  • act as a persistent data store for an extension

It would, IMHO, be clearer if each of these purposes was represented by a separate API (aka function)

simon

From the point of view of an extension author, extGetConfig () only returns the local values saved by an administrator in the hub. If you supply the default values in an array, it will merge these for your convenience. The 2 values '=dir' and '=url' may be useful for complex extensions but you can simply ignore. --Petko

It does not set default values, or store default values, or interface with the extension's form. The form values are set when the form is loaded, from any previously stored values, via $InputValues. In fact, it is recommended to not store default values, but to leave the fields empty, in order to keep the stored and loaded configuration smaller. --Petko

According to Cookbook.ExtensionDesign "You can ship a form page that will be included by the Hub when a wiki admin enables and configures your extension. The data that is saved by the administrator will be made available to your extension via the function extGetConfig()". The values entered on this form page are returned by $conf = extGetConfig () in the $conf array. These input field may be hard coded on the form, or generated by the extension.

Q: can the extension set form values on the extension's form

You could use (:input default name "value":), but as stated above, I recommend leaving the fields with default values empty. The form is not parsed when the the recipe is loaded on a wiki page, you must have your default values in your PHP script, like in the examples. --Petko

Your extension may provide a markup directive that generates form fields, see for example CodeHighlight which scans the resources directory to see which languages and color themes are available locally. This is what "input fields generated by the extension" means. --Petko

It appears the extension form can be invoked in three ways:

  • initially as part of PmWiki configuration.
    -- No. The form is loaded only when the ExtensionHub is used to configure the extension. Petko
    This is when function MyExtensionInit($pagename) {} might be used
    -- No, MyExtensionInit is used when the recipe is loaded. Petko
  • every time the extension's hub form is submitted
    -- No, the form is invoked before, not after it is submitted. The submitted values are saved in a text file. Petko
  • every time the extension form handles markup ( ... ) {} or $HandleActions []
    -- It is the other way around - when the hub form is loaded, and the extension is enabled, any custom markup in the form is handled by the recipe. The form you supply doesn't handle markup() or $HandleActions. Petko

Q: can the extension determine if it is being invoked for initiation, or for form processing? This could be useful to avoid repeating calling function MyExtensionInit() again.

There seems to be some misunderstanding, the whole logic is much simpler than you seem to assume (the complexity is supposed to be hidden from extension maintainers).

  • The MyExtensionInit () function is a suggestion in order to keep local all your temporary variables like $conf.
  • In the examples, MyExtensionInit () is called when the recipe is loaded, to allow you to get any locally stored values for the current page.
  • The values a user saves are stored in a text file which is later parsed, not in the form page you ship.
  • The text file stores all values for all extensions for all group.page patterns configurations.
  • extGetConfig() returns only those values that apply to your extension and to the current page.

--Petko

After you clarified you meant the "extension" not the "form", again I fail to understand what the problem is. The extension is loaded only when the user creates a configuration, defines page patterns, and selects "Enable", then the extension is loaded on these pages with this configuration. MyExtensionInit is not required, you are free to structure your code the way you want. When you want to get the local wiki values saved by the hub, use extGetConfig. You don't need to worry when the form is processed. If you add custom markup, whether in the form or in another wiki page, it will be available when the extension is enabled for the current page.

Extensions don't need to do anything when the form is saved, the extension enabled or disabled. I suspect you can check if $action is 'hub' and $_REQUEST['x'] is your extension name, but normally this should not be required. --Petko

Would it be possible to relax the pattern in extGetVersion() to allow it to match $RecipeInfo[EXTENSIONNAME]['Version'] = 'yyyy-mm-dd';?

simon

The pattern should already match your string (similar to RecipeInfo). What doesn't work is
$RecipeInfo[EXTENSIONNAME]['Version'] = 'yyyy-mm-dd' . $SomethingOrOther;
here 'yyyy-mm-dd' is returned. --Petko

PHP versions

I don't believe ExtensionHub should be constrained by, or support, unsupported versions of PHP.

simon

It needs to if we want to include it in the core, and enable a few extensions on pmwiki.org where Pm keeps version 7.0 and I suspect has no time to upgrade. Individual extensions are not constrained, as long as their supported versions are documented. --Petko

SDVA ()

What are the advantages of and reasons for using SDVA () to initialise the default configurations variables that are passed to extGetConfig ()?

simon

SDVA() "Set default values array" can be used it you want to allow for an administrator to redefine some of the default values in PHP, like in classic recipes. This may be desirable to reduce the configurations saved to disk, or in a wiki farm. --Petko

Resource in footer

I probably did something wrong, but a report could be useful: I tried extAddResource('mycookies.js', 1); in MyExtension.php, but cookies didn't work without the string $HTMLFooterFmt[]...$ExtPubDirUrl/... in farmconfig. Then I tried with priority 90, but at that point I couldn't log in anymore... so I had to delete the priority (line) manually from wiki.d/extensions/Extensions.Config. - Frank

It should probably be (for the footer):
extAddResource('mycookies.js', [], 1);
The second argument is an array of HTML attributes for the resources. I thought the resources in the header would be most frequently needed, attributes would be more frequently needed than footer resources. I was wondering if it would make it more obvious to switch the last 2 arguments (so your line would work). How do you feel about it? --Petko

Well, with the second argument yes, now cookies work, as you said. Having no attributes for the footer, I didn't think it was necessary. Sorry, dumb mistake. Thank you. - Frank

In order to simplify this and make it more obvious, I've added 2 helper functions extAddHeaderResource('mycookies.js'); and extAddFooterResource('mycookies.js'); in version 2024-04-10. The previous function still works. --Petko

Talk page for the ExtensionDesign recipe (users).