Groundhogg 4.9 rebuilt the flow editor: the canvas, the settings panels and the step picker are drawn in JavaScript, and each edit is saved as a small operation in the background instead of posting the whole flow. Together with changes from 4.8, this can affect add-ons that register flow step types or work with flows in code.
This page lists what changed since 4.7 that could break, or change the behaviour of, existing add-on code, and what to do about it. Most add-ons need no changes, but check the ones that apply to you. For how to register a step type with the new APIs, see Building Custom Flow Steps.
Requirements: these changes apply to Groundhogg 4.9 and later. Add-on code must still run on PHP 7.4.
Saving step settings
$_POST['steps']is no longer filled in. A step’s settings are saved on their own, from the fields in its open panel, and passed toStep::save()directly.get_posted_data(),setting_name_prefix()andsetting_id_prefix()work as before. Code that reads$_POST,$_REQUEST,get_post_var()orget_request_var()in a step’ssave()or sanitize callbacks won’t see the settings. Use$this->get_posted_data( 'key' ), or better, a settings schema instead ofsave().- Only the step’s own panel is sent. Inputs outside
#settings-{ID}, other steps’ fields, and the flow title aren’t in the request when a step is saved. Funnel.save()saves the open step. Called with no arguments (ortrue), it saves the open step’s panel and resolves once it’s saved. Hidden inputs added inside the panel before calling it are sent with it. The whole form is only posted when you passmoreData, which runs the oldprocess_edit()save, kept for compatibility.
Settings panels and the canvas
- Inline
<script>tags in settings output don’t run. The output ofsettings(),before_settings(),after_settings()andbefore_step_notes()is inserted by JavaScript, and browsers don’t run scripts inserted that way. Move the behaviour into your editor script, inFunnel.registerStepType(),registerStepCallbacks()‘onActive, or a delegated event listener. The element IDs fromsetting_id_prefix()haven’t changed. - The canvas is drawn in JavaScript from data the server sends for each step. Scripts that add to or change the canvas markup lose their changes on the next redraw. Use the
groundhogg/steps/sortable/classes,…/sortable/labelsand…/sortable/insidehooks instead. - Overriding
sortable_item()still works, but the step’s server markup is inserted as it is, without the add, move and duplicate buttons the editor now draws. If the override only adds classes or labels, remove it and use the hooks. - Panels are only redrawn when the server sends new settings HTML, not on every save, and never over a field the user is typing in.
Changed and new methods
A subclass that overrides one of these with a different signature causes a PHP warning on PHP 7.4 and a fatal error on PHP 8.
| Method | Change |
|---|---|
Funnel_Step::pre_save( Step $step, ?array $settings = null ) | New $settings parameter. Overrides must declare it. |
Step::save( ?array $settings = null ) | New $settings parameter: the settings to save, or null to read them from the editor’s request. Use Step::update_settings( [ … ] ) to change some settings from code. |
Funnel::commit( array $deleted_step_choices = [] ) | New parameter: what to do with contacts waiting at deleted steps. |
Form_Integration::field_map_table() | Removed. The field map is drawn in JavaScript. |
Benchmark::reset() | New public method, hooked to each of the trigger’s hooks (priority 97) to clear $this->data and $this->args before the trigger runs. A trigger class with a reset() method of its own now has it called every time its hook fires, and the trigger’s state isn’t cleared. Rename yours, or call parent::reset() from it. |
Funnel_Step: get_step_reference_settings(): array, get_canvas_data(), get_settings_island(), get_sortable_classes(), uses_custom_sortable_item(): bool, capture_output() | New methods. Rename any method of your own with the same name. |
Deleting steps
- Contacts waiting at deleted steps aren’t silently removed. When changes are published or a flow is activated, their events are cancelled (moved to the event history with the error code
step_deleted) or moved to another step, as the user chooses. Before, their events were deleted. - Deleted steps that contacts went through are archived (
step_statusarchived) instead of deleted, so their history still points at a real step. Queries on the steps table should excludearchivedanddeletedsteps, or check$step->is_active().Funnel::get_steps()already does. - Steps other steps point at can’t be deleted in the editor, for step types that declare
get_step_reference_settings().
Changing flows from code
- Wrap reads and writes of a flow’s draft in
$funnel->while_editing( function () { … } ). Outside it,Funnel::get_steps()on an active flow returns only the live steps, without new steps or staged changes. - Use
$step->update_settings( [ 'key' => $value ] )to change some of a step’s settings, so they’re sanitized and saved like in the editor. CallingStep::save( $settings )with a partial array resets the settings you leave out. - Steps are numbered in one sequence across all branches.
step_orderdoesn’t restart in each branch. - Only one person can edit a flow at a time. Other users can’t take over, and their saves are refused until the editor is closed.
Triggers
- “Can be triggered” limits are enforced. “At most once per contact” and “Up to X times per contact” were never applied before. Triggers that relied on firing every time may now be skipped.
- Trigger state is reset each time its hook fires. Step elements are shared objects, so a trigger firing for several contacts in one request used to carry the first contact’s data. Don’t rely on data kept on the element between hook calls. Also,
$this->argsis no longer merged with the data’s arguments and written back after a step is completed. - Object arguments passed to triggers are reduced to their ID with
get_id()first, then a publicIDoridproperty. Objects with both, likeWC_Order, now give the value ofget_id().
Hooks and other changes
groundhogg/funnel/import/afternow passes the import data as its second argument. It used to pass the last imported step’s data.- The
Legacy_Contact_Queryclass, deprecated since 3.2, has been removed. UseContact_Query. - Since 4.8, Groundhogg’s admin scripts don’t load select2. When it isn’t loaded,
.select2()is a lightweight replacement that supports the options Groundhogg uses (data,ajax,multiple,tags,placeholder,allowClear). Load select2 yourself if you need more of its API. - Since 4.8, the
view_noteandview_taskcapabilities (and their edit and delete versions) also check access to the contact, deal or company the note or task belongs to.
Updating an add-on: checklist
- Each step’s settings are inputs inside its panel named with
setting_name_prefix(), or set withupdate()/Funnel.updateStepMeta(). - No step reads settings from
$_POSTor other request variables. Better still, each step usesget_settings_schema()instead ofsave(). - No inline
<script>in settings output; editor behaviour lives in a script that depends ongroundhogg-admin-funnel-editor. - Overrides of
pre_save()and other changed methods match the new signatures. - Queries on the steps table skip
archivedanddeletedsteps. - Settings that hold step IDs are declared with
get_step_reference_settings(). - Optionally: settings drawn with
Funnel.registerStepType(), and the step described for abilities withStep_Type_Schema::extend(). - Tested in the editor: add the step, change each setting, reload, duplicate, undo and redo, then run a test contact through it.
Was this helpful?
Let us know if this document answered your question. That’s the only way we can improve.
