4.9 Breaking Changes for Developers

📅 Published on

📝 Last updated

Documentation

»

Known Issues & Workarounds

»

4.9 Breaking Changes for Developers

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 to Step::save() directly. get_posted_data(), setting_name_prefix() and setting_id_prefix() work as before. Code that reads $_POST, $_REQUEST, get_post_var() or get_request_var() in a step’s save() or sanitize callbacks won’t see the settings. Use $this->get_posted_data( 'key' ), or better, a settings schema instead of save().
  • 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 (or true), 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 pass moreData, which runs the old process_edit() save, kept for compatibility.

Settings panels and the canvas

  • Inline <script> tags in settings output don’t run. The output of settings(), before_settings(), after_settings() and before_step_notes() is inserted by JavaScript, and browsers don’t run scripts inserted that way. Move the behaviour into your editor script, in Funnel.registerStepType(), registerStepCallbacks()‘ onActive, or a delegated event listener. The element IDs from setting_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/labels and …/sortable/inside hooks 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.

MethodChange
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_status archived) instead of deleted, so their history still points at a real step. Queries on the steps table should exclude archived and deleted steps, 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. Calling Step::save( $settings ) with a partial array resets the settings you leave out.
  • Steps are numbered in one sequence across all branches. step_order doesn’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->args is 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 public ID or id property. Objects with both, like WC_Order, now give the value of get_id().

Hooks and other changes

  • groundhogg/funnel/import/after now passes the import data as its second argument. It used to pass the last imported step’s data.
  • The Legacy_Contact_Query class, deprecated since 3.2, has been removed. Use Contact_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_note and view_task capabilities (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 with update() / Funnel.updateStepMeta().
  • No step reads settings from $_POST or other request variables. Better still, each step uses get_settings_schema() instead of save().
  • No inline <script> in settings output; editor behaviour lives in a script that depends on groundhogg-admin-funnel-editor.
  • Overrides of pre_save() and other changed methods match the new signatures.
  • Queries on the steps table skip archived and deleted steps.
  • Settings that hold step IDs are declared with get_step_reference_settings().
  • Optionally: settings drawn with Funnel.registerStepType(), and the step described for abilities with Step_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.