Accessing services

The core of Torro Forms consists of several services all of which you can access through the main plugin class instance. Each service is responsible for a specific part of functionality or content and is based on a common foundation. The majority of services are instantiated in the Torro_Forms plugin class and can then be retrieved through a method of the respective service’s name. Since the Torro_Forms plugin class instance can be retrieved via the global torro() function, you can easily chain method calls to request a service. For example, to get access to the form manager service, call torro()->forms(). Or, to get access to the options handler of the plugin, call torro()->options().

Some services also require other services, and those are then available from their dependants as well. For example, the form manager service requires the metadata service, so you can access that instance via torro()->forms()->meta().

If you need to use a service for more than just one simple task, it’s recommended to store it in a variable.

function myextension_create_or_get_form( $id ) {
	// We store the form manager service in a variable.
	$forms = torro()->forms();
	$form = $forms->get( $id );
	if ( ! $form ) {
		$form = $forms->create();
		$form->sync_upstream();
	}
}

Otherwise, for single tasks, you can simply use chaining to call the method you need.

function myextension_get_option( $option, $default = false ) {
	// We access the get() method of the options service directly.
	return torro()->options()->get( 'myextension_' . $option, $default );
}

Available services

Here is a list of all available services from the Torro Forms core plugin:

torro()

  • ->forms(): Create, read, update and delete forms.
  • ->containers(): Create, read, update and delete containers (individual pages of a form).
  • ->elements(): Create, read, update and delete elements (individual fields of a container).
  • ->element_choices(): Create, read, update and delete element choices (choices to pick from for elements that support that).
  • ->element_settings(): Create, read, update and delete element settings (settings and behavior for elements).
  • ->submissions(): Create, read, update and delete submissions (a set of user-submitted data for a form).
  • ->submission_values(): Create, read, update and delete submission values (individual values of a submission).
  • ->form_categories(): Create, read, update and delete form categories (internal means to categorize forms).
  • ->modules(): Register, unregister and retrieve plugin modules (and submodules), registered by the core plugin or its extensions.
  • ->options(): Retrieve and store arbitrary options.
  • ->meta(): Retrieve and store arbitrary metadata of a certain object type.
  • ->cache(): Retrieve and store arbitrary values using the WordPress cache mechanism.
  • ->db(): Manage the database tables of the plugin, or make direct database requests.
  • ->assets(): Register and enqueue plugin scripts and stylesheets.
  • ->template(): Include plugin template files, or register alternative template directories.
  • ->ajax(): Register AJAX actions for the plugin, or get the security nonce to perform an action.
  • ->post_types(): Register, unregister and access post types.
  • ->taxonomies(): Register, unregister and access taxonomies.
  • ->admin_pages(): Register admin pages.
  • ->extensions(): Register and access plugin extensions.
  • ->form_uploads(): Handle form file uploads.
  • ->template_tag_handlers(): Register, unregister and retrieve template tag handlers.
  • ->error_handler(): Handle functionality errors, like throwing deprecated notices.

As you can see, some services manage the database content that the plugin provides, others provide more low-level APIs or wrap around existing WordPress core functionality in an object-oriented fashion. Even the latter services are useful though, since they namespace everything, to prevent conflicts with other plugins. That means, that if you call for example torro()->options()->update( 'my_extension_setting', true ), the option stored internally will actually be called torro_my_extension_setting.

Using services in your extension

For the most part, you’ll likely be able to use the services from the main plugin, for example when accessing form content, managing modules or retrieving and storing options. Remember, you can retrieve the plugin’s options service via torro()->options() for example. If you’re writing an actual extension and thus have an extension class you’re using, you don’t even need to call the torro() function, since the plugin main class instance is also available as a property in your extension class. From there, you could just use $this->parent_plugin->options() instead of the above.

In some cases however, you may find it useful to have your own service instance, specific to your extension. For example, the plugin’s options service instance (torro()->options()) prefixes all options with “torro_”. If your extension has quite a few settings of its own, you might wanna create your own instance where you set the prefix to something like “torro_my_extension_”, so that that whole prefix is then applied automatically without you being required to type it in every call to retrieve or update an option.

Another even more common example is enqueuing assets, like scripts and stylesheets. The core plugin’s assets service only handles assets from the plugin directory. If your extension includes some assets of its own, you actually need to have your own instance of the assets service.

Instantiating services

Before you continue reading, make sure you are familiar with writing an extension for Torro Forms.

To have a custom service instance in your extension, you first need to declare a property on your extension class to store it. For example, if you wanna have a custom assets instance, call the property $assets. Choose the property name wisely since it will be the same name that your service instance can be accessed through later, via a magic method.

After that, all you need to do instantiate the service, which should happen in your extension class’s instantiate_services() method.

protected function instantiate_services() {
	$this->assets = new Leaves_And_Love\Plugin_Lib\Assets\Assets( 'torro_my_extension_', array(
		'path_callback'  => array( $this, 'path' ),
		'url_callback'   => array( $this, 'url' ),
		'plugin_version' => $this->version,
	) );
}

The first parameter for every service constructor is the prefix it should use. The other parameters (if any) are specific to the service’s implementation. The assets service for example requires certain arguments to know where to look for assets and which version string to apply, that’s why those arguments are passed in the above sample code. And that’s it already – you can now use your extension’s service!

Internals of a service

If you are in need of writing your own service for an extension, this section provides you with more information. Before going into details though, be aware that this should only be necessary if your extension introduces very foundational completely new features that are not based on any existing, more targeted API present in Torro Forms. For most extension points, the core plugin already provides a solid foundation for that you should use instead of implementing a new service. If you’re still sure you need your own, let’s continue.

A service always inherits the Leaves_And_Love\Plugin_Lib\Service class which is part of the underlying plugin library Torro Forms bundles. As its minimum a service always contains a get_prefix() method which returns the prefix it is using for its internal functionality integrating with WordPress core. Furthermore there are common traits that services may use:

  • Leaves_And_Love\Plugin_Lib\Traits\Hook_Service_Trait: Adds add_hooks() and remove_hooks() methods that add/remove all hooks necessary for the class to interact with WordPress. The implementation also supports protected or private methods to be hooked in. When writing your own service that includes hooks, use this trait and implement the protected setup_hooks() method. Then, call that method from the constructor.
  • Leaves_And_Love\Plugin_Lib\Traits\Container_Service_Trait: Allows to require other services that then need to be passed into the constructor as a $services parameter. Services can then be retreived with the name of the service called as a method. When writing your own service that requires other services, use this trait and define each service as a class property with that service’s class name as value. Then, in the constructor require a $services parameter and call set_services( $services ) from there.
  • Leaves_And_Love\Plugin_Lib\Traits\Args_Service_Trait: Allows to support certain behavioral arguments to be passed into the constructor as $args parameter. Argument values can then be retrieved by simply accessing them (since they become magic properties). When writing your own service that supports arguments, use this trait and define a protected static method with the name parse_arg_{arg_name}(), which takes a given value as parameter (or null if none provided) and parses it into a value valid for that argument which must be returned. You can also return a default here if no value is provided. Then, in the constructor, support an optional $args parameter and call set_args( $args ) from there.
  • Leaves_And_Love\Plugin_Lib\Traits\Translations_Service_Trait: Allows to require a Leaves_And_Love\Plugin_Lib\Translations\Translations object with translations to be passed into the constructor as $translations parameter. A protected get_translation( $identifer, $noop = false ) will be available that returns a translated string for a message identifier. This decouples translation strings from the actual code they’re used in, so it is only recommended if you’re writing code that should be reused across multiple plugins (since translation strings for a textdomain should always be part of the plugin with that textdomain, not of a library or different plugin). When writing your own service that requires a translations object, use this trait and create a translations class with the strings. It’s recommended to follow the naming pattern of Translations_{Original_Class_Name_Without_Namespaces}. Then, in the constructor require a $translations parameter and call set_translations( $translations ) from there.

If you need to write your own service, a good idea is to look at an existing service and see how they use the above traits in detail. However, as said before, this mostly shouldn’t be necessary.