Docs / Developers

The example add-on plugin

A complete, working add-on ships inside Craftor's own plugin folder.

Craftor's plugin folder includes examples/craftor-hello-addon — a real, single-file WordPress plugin you can copy into wp-content/plugins, rename, and build on directly. Activate it alongside Craftor and it registers:

  • A "Callout (Hello Add-on)" widget — heading, message, and background color controls.
  • A "Log Submission (Hello Add-on)" workflow action — appends each submission to a small rolling log (a WordPress option), so it works immediately with nothing else to configure.
  • Two lifecycle hooks in use: craftor/form/after_submit (writes to the PHP error log) and craftor/email/headers (Bcc's every form notification to the site admin).
php
add_action( 'plugins_loaded', 'craftor_hello_addon_bootstrap' );

function craftor_hello_addon_bootstrap(): void {
	if ( ! class_exists( '\Craftor\Widgets\AbstractWidget' ) ) {
		return; // Craftor isn't active.
	}

	craftor_hello_addon_define_classes(); // declares the widget + action classes

	add_action( 'craftor/register_widgets', 'craftor_hello_addon_register_widget' );
	add_action( 'craftor/register_workflow_actions', 'craftor_hello_addon_register_action' );
	add_action( 'craftor/form/after_submit', 'craftor_hello_addon_log_submission', 10, 6 );
	add_filter( 'craftor/email/headers', 'craftor_hello_addon_bcc_admin_on_notifications', 10, 3 );
}

Notice the widget/action classes are declared inside a function (craftor_hello_addon_define_classes()), called only after the class_exists() check passes — not as top-level `class Foo extends ...` statements. This sidesteps a real plugin-load-order bug: WordPress loads active plugins in an unspecified order, and a top-level extends of a Craftor base class can fatal if your file happens to load before Craftor's own. Keep the same structure in your own add-on.