Skip to content

feat(integrations): add WSMS (WP SMS) integration#183

Open
RishadAlam wants to merge 4 commits into
mainfrom
feat/wp-sms
Open

feat(integrations): add WSMS (WP SMS) integration#183
RishadAlam wants to merge 4 commits into
mainfrom
feat/wp-sms

Conversation

@RishadAlam

Copy link
Copy Markdown
Member

Description

Adds the WSMS (formerly WP SMS) integration to Bit Integrations — 5 wp_hook triggers and 7 write actions for sending SMS/MMS and managing subscribers and groups. The Free plugin ships the action UI and fires the bit_integrations_wsms_* hook bridge; the actual WP SMS work lives in the Pro add-on.

Motivation & Context

WSMS is a widely-used WordPress SMS/MMS plugin but had no Bit Integrations support. This lets flows send SMS/MMS and react to WSMS subscriber/group events.

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 💥 Breaking change
  • 📚 Documentation update
  • ⚡ Improvement
  • 🔄 Code refactor

Key Changes

Integrations (Backend)

  • Added Actions/Wsms/WsmsController (authorize + group dropdown data), RecordApiHelper (dispatches the 7 actions through bit_integrations_wsms_* filters), Routes
  • Added the Wsms entry in AllTriggersName

Frontend

  • Added the WSMS action UI: action select, field maps, group dropdown and a static Active/Inactive status select
  • Added registration in the New/Edit/Info integration switches, SelectAction, the custom_form_submission trigger list, and the integration icon

Fixes (code review)

  • Fixed the field-map select to compare against requiredFlds.length and bind to the field key (the locked required-field branch never ran before)
  • Fixed stale groupId/status leaking across actions by clearing them when the action changes
  • Improved the status list to a static frontend constant instead of a backend AJAX round-trip for two constants

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Tests added/updated
  • Documentation updated if needed
  • README updated if needed

Changelog

  • New Integration: WSMS (WP SMS) — send SMS/MMS and manage subscribers and groups directly from your flows.
  • New Triggers: SMS Sent, OTP Generated, Subscriber Added, Subscriber Verified, Number Unsubscribed.
  • New Actions: Send SMS, Add/Update/Delete Subscriber, Add/Update/Delete Group.

- 5 wp_hook triggers: SMS Sent, OTP Generated, Subscriber Added, Subscriber
  Verified, Number Unsubscribed (custom_form_submission, logic in Pro)
- 7 actions (all Pro): Send SMS; Add/Update/Delete Subscriber; Add/Update/Delete
  Group. Update Subscriber is identified by mobile number and Update/Delete Group
  by group_id via the field map; subscriber actions expose group + status
  dropdowns
- Free fires bit_integrations_wsms_* filters and serves group/status dropdown
  data; registered in AllTriggersName, the New/Edit/Info integration switches,
  SelectAction, plus the integration icon
…ntegrations

Add B2BKing, FormyChat, GiveWp, SenseiLMS, SureDash, WpDataTables, WpErp
and Wsms to the customFormIntegrations list. These Pro triggers declare
type custom_form_submission but were absent from the frontend list, so
they were not handled as custom-form integrations in the UI.
- WsmsFieldMap: compare i < requiredFlds.length (was missing .length, so the
  locked required-field branch never ran) and bind the select value to the
  field key, not its label
- WsmsIntegLayout: clear groupId/status when the action changes so a previous
  action's dropdown selection no longer leaks into the next one
- statuses are now a static frontend list (wsmsStatuses) instead of a backend
  AJAX round-trip for two constants — removes the refreshStatuses route/method
  and the loading-state race with refreshGroups

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new integration for WSMS (WP SMS), adding backend controllers, routes, and helpers to handle actions like sending SMS and managing subscribers/groups, alongside frontend React components for authorization and field mapping. The review feedback suggests declaring helper methods as static where appropriate, correcting a typo in a translation string, adding error handling to the authorization fetch request to prevent stuck loading states, and safely rendering multi-select options using a ternary operator instead of logical AND.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

return $response;
}

private function generateReqDataFromFieldMap($fieldMap, $fieldValues)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The method generateReqDataFromFieldMap is called statically on line 47 (static::generateReqDataFromFieldMap) but is declared as an instance method. Since it does not access any instance properties ($this), it should be declared as static to adhere to PHP best practices and avoid potential warnings.

    private static function generateReqDataFromFieldMap($fieldMap, $fieldValues)
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — declared generateReqDataFromFieldMap as static (it uses no instance state and is already called via static::).

Comment thread backend/Actions/Wsms/WsmsController.php Outdated
wp_send_json_success(true);
}

public function refreshGroups()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The method refreshGroups does not access any instance properties ($this) and is registered as a static callback in Routes.php. It should be declared as static to adhere to the project's coding standards.

    public static function refreshGroups()
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — declared refreshGroups as static (no $this usage; registered as a static route callback, consistent with wsmsAuthorize).

$defaultResponse = [
'success' => false,
// translators: %s: Plugin name
'message' => wp_sprintf(__('%s plugin is not installed or activate', 'bit-integrations'), 'Bit Integrations Pro')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a typo in the translation string: 'activate' should be 'activated' to be grammatically correct and consistent with line 43.

            'message' => wp_sprintf(__('%s plugin is not installed or activated', 'bit-integrations'), 'Bit Integrations Pro')

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — fixed the typo to "activated".

Comment on lines +20 to +33
const authorizeHandler = () => {
setIsLoading('auth')
bitsFetch({}, 'wsms_authorize').then(result => {
if (result?.success) {
setIsAuthorized(true)
setSnackbar({
show: true,
msg: __('Connected with WSMS (WP SMS) Successfully', 'bit-integrations')
})
}
setIsLoading(false)
setShowAuthMsg(true)
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the bitsFetch request fails or encounters a network error, the promise will reject and the .then block will not execute. This leaves the loading state (isLoading) stuck as 'auth'. Adding a .catch block ensures that the loading state is cleared and the error message is shown.

  const authorizeHandler = () => {
    setIsLoading('auth')
    bitsFetch({}, 'wsms_authorize')
      .then(result => {
        if (result?.success) {
          setIsAuthorized(true)
          setSnackbar({
            show: true,
            msg: __('Connected with WSMS (WP SMS) Successfully', 'bit-integrations')
          })
        }
        setIsLoading(false)
        setShowAuthMsg(true)
      })
      .catch(() => {
        setIsLoading(false)
        setShowAuthMsg(true)
      })
  }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added a .catch so the loading state clears and the auth message shows on a failed/rejected request.

.catch(() => {
  setIsLoading(false)
  setShowAuthMsg(true)
})

Comment on lines +74 to +81
options={
wsmsConf?.allGroups &&
Array.isArray(wsmsConf.allGroups) &&
wsmsConf.allGroups.map(group => ({
label: group.label,
value: group.value?.toString()
}))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using logical AND (&&) for conditional rendering or prop assignment can result in false or undefined being passed to the options prop of MultiSelect if allGroups is not set or is not an array. It is safer and more robust to use a ternary operator and default to an empty array [] to prevent potential component rendering issues.

Suggested change
options={
wsmsConf?.allGroups &&
Array.isArray(wsmsConf.allGroups) &&
wsmsConf.allGroups.map(group => ({
label: group.label,
value: group.value?.toString()
}))
}
options={
Array.isArray(wsmsConf?.allGroups)
? wsmsConf.allGroups.map(group => ({
label: group.label,
value: group.value?.toString()
}))
: []
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — switched the options to a ternary that defaults to [] when allGroups is unset/not an array.

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

🔍 WordPress Plugin Check Report

⚠️ Status: Passed with warnings

📊 Report

🎯 Total Issues ❌ Errors ⚠️ Warnings
1 0 1

⚠️ Warnings (1)

📁 readme.txt (1 warning)
📍 Line 🔖 Check 💬 Message
0 mismatched_plugin_name Plugin name "Bit integrations - Form Integration, Webhook, Spreadsheets, CRM, LMS & Email Automation" is different from the name declared in plugin header "Bit Integrations".

🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check

- RecordApiHelper: declare generateReqDataFromFieldMap static (no instance state,
  already called via static::); fix "activate" -> "activated" typo
- WsmsController: declare refreshGroups static (no $this, static route callback)
- WsmsAuthorization: add a .catch so loading clears and the auth message shows
  on a failed/rejected request
- WsmsIntegLayout: default the group options to [] via a ternary instead of &&
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant