Philstack's iMIS SSO Plugin for WordPress — Documentation

Plugin version: 3.13.0
Requires: WordPress 5.2+, PHP 7.2+, the php-curl extension
Author: Philstack LLC — support: [email protected]

Authenticate users into WordPress with the iMIS EMS Enterprise built-in OAuth SSO. The plugin signs members into WordPress using their iMIS credentials, synchronizes their profile data and roles from iMIS on every login, and provides role-based security for pages, posts, and media library documents.

How It Works

The plugin uses iMIS as the identity provider. iMIS must be the login page.

  1. A visitor requests secured content (or clicks a login button) and is redirected to the iMIS SSO login page.
  2. After entering credentials in iMIS, the visitor is redirected back to the WordPress SSO Return URL — a built-in plugin endpoint — with a refresh token.
  3. The plugin exchanges the refresh token for an access token, then fetches the user's details from the $/Philstack/UsernameData IQA query (and, optionally, committee data from $/Philstack/UsernameDataCommittees).
  4. The plugin matches the iMIS user to a WordPress user (by email, username, or full name, per your settings) or creates a new WordPress account.
  5. The user's profile (first name, last name, email) is updated, custom mapped fields are synced to user meta, and WordPress roles are synchronized with the current iMIS data.
  6. The user is logged into WordPress and returned to the page they originally requested. If the original page cannot be determined, the Fallback Return URL is used.

Requirements & Setup Overview

Step-by-step setup instructions with screenshots are available on the Philstack website.

Admin Menu Reference

The plugin adds a top-level Philstack's iMIS SSO menu to the WordPress admin (requires the manage_options capability, i.e. administrators).

Admin → Philstack's iMIS SSO

The main plugin page. It shows:

Admin → Philstack's iMIS SSO → Secured Content

A list table of every post, page, custom post type item, and media document that has role-based security assigned (anything with security roles saved on it).

Use this screen to audit exactly which content on the site is restricted and to whom.

Admin → Philstack's iMIS SSO → Role Manager

Create, rename, and delete WordPress roles without a separate role-editor plugin.

Roles created here (or automatically by the SSO role sync) can be used in the page and document security role pickers.

Admin → Philstack's iMIS SSO → Documentation

Opens this documentation (the flat-file HTML version bundled with the plugin) in a new browser tab, so the full reference is always available for the exact plugin version installed.

Settings Reference

All settings live on the main Philstack's iMIS SSO page and are stored together in one WordPress option (ps_imis_sso_plugin_options).

Licensing

SettingDescription
License KeyThe license key provided by Philstack. All features are enabled once a valid license is entered. See License Validation for caching/grace-period behavior.

iMIS URL and Client Application Settings

SettingDescription
iMIS URLThe base URL of your iMIS instance. Include the https:// prefix and add nothing after the domain (example: https://acme.imiscloud.com).
Client IDThe client application ID configured in iMIS for this integration.
Shared SecretThe client application shared secret from iMIS. Stored in the WordPress options database.
SSO Return URLRead-only. The plugin's built-in SSO return endpoint (/?ps_sso_endpoint=return, with the pretty alias /ps-sso-return/ also registered). Configure this URL in iMIS as the SSO redirection target. No WordPress page and no [ps-sso-return] shortcode is required.

Redirection Settings

These control redirection behavior before, during, and after the SSO.

SettingDescription
Login URLFull URL of the iMIS SSO redirector page (the iMIS-hosted login entry point).
Login button labelLabel for the login state of [ps-sso-auth-button] and the nav-menu Login item. Default: Login.
Login Redirector URLOptional; leave blank. Original-requested-page tracking now runs on the plugin's built-in login endpoint, so users land back where they started with nothing configured. Set this only if you are still using a page containing the legacy [ps-sso-login-redirector] shortcode. The panel shows which URL is currently in use.
Fallback Return URLFull URL used after SSO when the originally requested page cannot be determined.
Access Denied URLFull URL where logged-in users land when they lack access to the requested content. If blank, the site homepage is used.
Logout URLFull URL where the browser lands after the user clicks the Sign Out button.
Single Logout (iMIS 20.3.228+)Checkbox. Switches from the legacy redirect logout to the iMIS single-logout (front-channel) model. See Logout & Single Logout. The settings panel also displays the WordPress front-channel endpoint URL to paste into your iMIS SingleLogout content record.
iMIS Logout Endpoint URLSingle Logout only. The iMIS endpoint the browser calls to end the iMIS session. Leave blank to derive {iMIS URL}/Authentication/Logout automatically.
Logout button labelLabel for the logout state of [ps-sso-auth-button] and the nav-menu Logout item. Default: Logout.
Profile page URLDestination for [ps-sso-profile-button].
Profile button labelLabel for [ps-sso-profile-button]. Default: Profile.
Renewal page URLDestination for [ps-sso-renewal-button] and [ps-sso-renewal-banner].
Renewal button labelLabel for [ps-sso-renewal-button]. Default: Renew Now.
Renewal not available messageText shown by [ps-sso-renewal-button] when the logged-in user is not eligible for renewal. Default: Renewal not available.
Renewal banner textLink text for [ps-sso-renewal-banner]. Default: Renew Your Membership.

Authorization Required Message

Controls what happens when someone hits secured content, as an alternative to redirecting.

SettingDescription
Display Authorization Required Message instead of RedirectCheckbox. When checked, not-logged-in visitors to secured content see a message in place of the content instead of being redirected to the login flow.
Authorization Required MessageRich-text (HTML) message shown to not-logged-in visitors when the option above is on. Shortcodes are supported. Default: "Authorization required. Please log in to access this content."
Display Access Denied Message instead of RedirectCheckbox. When checked, logged-in users without a required role see a message in place of the content instead of being redirected to the Access Denied URL.
Access Denied MessageRich-text (HTML) message shown to logged-in users without access when the option above is on. Shortcodes are supported. Default: "You do not have permission to access this content."

Both behaviors are global defaults — every secured page/post can override them individually in its security meta box. Combine with the [ps-sso-content-gate] shortcode to show a public teaser above the message.

Secured Documents

SettingDescription
Enable Secured DocumentsCheckbox. Extends role-based security to media library files (PDFs, images, zips, etc.). When enabled, a Philstack Document Security panel appears on every media item. Securing a file moves it into a protected store so its public URL is routed through WordPress for a role check — no server configuration required; works on Apache and Nginx/managed hosts. When disabled, all secured files are moved back to their public locations and served normally again (per-document settings are preserved for instant re-enable). A warning and confirmation appear if you disable the feature while documents are secured.
Optional host rewrite rule (WP Engine / static-uploads hosts)Expandable panel. Most hosts work out of the box. Hosts that serve /wp-content/uploads/ statically and hard-404 missing files (e.g. WP Engine) need one regex redirect rule — shown in this panel with copy-ready Redirect from / Redirect to values — so raw document URLs are routed through WordPress for the access check. On WP Engine add it in the Web Rules Engine using the Internal Rewrite action so the raw URL stays in the address bar. Note: every matching file (including public ones) is then delivered through PHP instead of the CDN.
"I have installed the host rewrite rule above"Checkbox inside the panel above. When checked, secured documents render their original /wp-content/uploads/ URL instead of the /ps-protected-document/ handler URL, since the host rule already routes raw URLs through WordPress. Leave unchecked if you have not added the rule, or links to secured files will 404 on static-uploads hosts.

Access behavior for a secured document:

Role Assignment Settings

SettingDescription
Use the iMIS IQA "sso-role" field as the WordPress roleCheckbox. When checked, each user's main WordPress role is derived from the sso-role code returned by the UsernameData IQA (a matching role is created automatically if needed, with Subscriber capabilities). When unchecked, the Default role below is used.
Default roleThe WordPress role assigned when the checkbox above is not checked. Default: Subscriber.
Role to exempt from the SSO role update processUsers holding this role are skipped by role synchronization — their roles are never added or removed by SSO. WordPress administrators are always automatically exempt. Default: Administrator. Note: exemption protects role assignments only; profile data and custom fields still sync.

Username Matching Settings

Selects how the plugin matches incoming iMIS users to existing WordPress accounts (and how usernames are generated for new accounts):

OptionDescription
Match by Email Address (default)Matches the iMIS user's email address to a WordPress account. New accounts use the email as the username (falling back to imis_{id} if taken).
Match by First Name + Last NameConcatenates the iMIS first and last name to match the WordPress username; spaces and special characters are removed or replaced (e.g. "John Doe" → johndoe). New usernames get the iMIS ID appended if taken.
Match by iMIS UsernameMatches the iMIS username field directly to the WordPress username.

If no match is found, a new WordPress user is created using the selected method. If the iMIS email already belongs to a different WordPress account, the new account is created with a modified, unique email to avoid the conflict (logged in debug mode).

Custom iMIS Field Sync

Sync additional iMIS IQA columns (e.g. academic or personalization data) into WordPress user meta on every SSO login — no code and no extra API calls required.

SettingDescription
Enable Custom Field SyncCheckbox, off by default. When enabled, the fields mapped below are stored as user meta on every SSO login. When disabled (or when a mapping is removed), previously synced values are cleaned up on each user's next login.
Field mappingsTextarea, one mapping per line: imis-column-name or imis-column-name => meta_key. Column names must match the IQA output exactly (matching is case-insensitive). If no meta key is given, one is derived from the column name. Lines starting with # are comments. An Active mappings preview table below the field shows exactly which iMIS column maps to which user meta key and the ready-to-copy [ps-sso-user-field] shortcode for each.

Details:

WordPress UI Settings

SettingDescription
Hide WordPress Admin BarCheckbox. When enabled, the WordPress admin toolbar is hidden on the front end for all users except administrators.

Debug Settings

SettingDescription
Debug ModeCheckbox. Enables verbose SSO flow logging (user matching, role assignment, redirects, API responses). The log is displayed by the [ps-sso-welcome] shortcode and stored in the browser session (cleared when the browser closes). Additional detail is written to the PHP error log.
Skip cURL cert validationCheckbox — for local/development testing only. Disables TLS certificate verification on API calls. Never enable in production.
Store iMIS Committee data as user metaCheckbox. When enabled, committee assignments from the $/Philstack/UsernameDataCommittees IQA are fetched on each login, stored in user meta (imis_committee_data), displayed on the user's profile screen, and used to assign iMIScommittee_-prefixed WordPress roles. When disabled, the committee API call is skipped, stored committee meta is cleared, and stale committee roles are removed on the next login.

Content Security Tools

Role-Based Page Security (meta box)

Every public post type's edit screen (posts, pages, custom post types) gets a Philstack Role-Based Page Security meta box in the sidebar:

The block editor shows a persistent notice banner stating whether the current page is public or restricted (and to which roles), updating live as you change the checkboxes.

Both custom-message boxes are full rich-text (WYSIWYG) editors with Visual and Text tabs. Under the block editor, WordPress relocates meta boxes in the page after they render, which can leave a rich-text editor visible but impossible to click into or type in; as of 3.12.2 the plugin detects that state and re-initializes the editor automatically, so no action is needed.

Teaser previews: place [ps-sso-content-gate] in the content to show everything above it publicly while gating everything below it (see the Shortcode Reference).

Message display replaces only the protected post's own content. Site furniture rendered by the theme — the sitewide footer, headers, sidebars, widgets, and secondary loops such as related-post lists — is left untouched and continues to display normally on a gated page.

Secured pages appear in the Secured Content admin list.

Document Security (media library panel)

With Secured Documents enabled, every media item (in both the media modal and the Edit Media screen) gets a Philstack Document Security panel:

If a secured file cannot be moved into the protected store (e.g. the uploads directory is not writable), an admin notice appears and the file may still be publicly accessible until permissions are fixed and the media is re-saved.

Appearance → Menus gains a PS-SSO Authentication box that adds smart Login and Logout items to any menu:

User Profile Panels

On the WordPress user profile screen (Users → Profile / Edit User), the plugin displays:

Shortcode Reference

[ps-sso-return] — deprecated

No longer required. The SSO token exchange runs on the built-in SSO Return URL endpoint; point iMIS there instead of at a page. The shortcode is kept so existing installs keep working, and a page containing it can be deleted once iMIS is repointed.

When it does run, the plugin exchanges the token, fetches the user's iMIS data, logs them into WordPress, and forwards them to their original page (or the Fallback Return URL). Renders nothing on a normal visit; requires a valid license.

Execution point. Logging a user in sets an authentication cookie, and both that cookie and the final redirect are HTTP headers — so they can only be sent before the page produces output. The built-in endpoint runs on parse_request, before WordPress has even resolved a post. The legacy page flow runs on template_redirect, before the theme emits anything, with the shortcode itself as a last-resort fallback.

For the legacy page flow this matters because the page is detected by looking for the shortcode in the post content, not by waiting for it to render. A theme or page builder that never calls the_content() would otherwise skip the login entirely. Either way, a successful SSO return always responds with a 302 redirect and never a 200 HTML page.

Troubleshooting: if a POST to the SSO return page responds 200 OK with a rendered page instead of a 302, the login did not complete. On plugin versions before 3.12.1 this was the expected symptom when PHP output buffering was disabled — the <head> had already been sent, so wp_set_auth_cookie() and wp_redirect() both failed silently. Enable Debug Mode and check the log for Headers already sent: YES.

Trailing slashes. Configure the iMIS SSO return URL to match the WordPress permalink exactly, including a trailing slash if your permalink structure uses one (https://example.org/sso-return/). WordPress skips canonical redirects on POST requests, so a mismatch usually works — but any redirect placed in front of a POST discards the request body and the refresh token along with it.

[ps-sso-login-redirector] — deprecated

No longer required. Original-page tracking runs on the plugin's built-in login endpoint and is on by default; leave Login Redirector URL blank to use it. The shortcode is kept so existing installs keep working, and the page containing it can be deleted once the setting is cleared.

The behavior is identical either way: when a visitor arrives with a redirect_to query parameter, the redirector stores the originally requested URL (redundantly, via cookie, PHP session, and database transients, to survive restrictive hosting/CDN configurations) and forwards the visitor to the iMIS login page. After SSO completes, the visitor is returned to the stored URL. Already-logged-in visitors are sent straight back.

For security, redirect_to values pointing off-site are rejected and ignored — visitors are only ever returned to a URL on this site.

Page caching. The redirector is a pure side-effect page: it must execute PHP on every visit to work at all. If a full-page cache stores its response, PHP stops running and the login link silently does nothing. The plugin defends against this automatically:

Editor safety. Both deprecated shortcodes have side effects — they set cookies, redirect, and exit. They now run only on live front-end page views: they are inert during admin, REST, AJAX, cron, feed, preview, and Elementor editor/preview requests, showing administrators a short placeholder instead. Rendering one during a REST save is what previously made publishing a page containing either shortcode fail with "Updating failed. The response is not a valid JSON response."is_admin() returns false during a REST request, so the old guard never caught it.

If the login redirector stops working on a cached production site, enable Debug Mode and check the SSO log for Login redirector initialized. If that entry is absent after a failed login attempt, the request never reached PHP and the response is being served from a cache layer that is ignoring the headers above; exclude the redirector and SSO return URLs from the host's page cache.

[ps-sso-auth-button]

Displays a Login button for anonymous visitors or a Logout button for logged-in users. Labels and destinations come from the Redirection Settings. The login button routes through the login redirector (carrying the current page as redirect_to) — the configured Login Redirector URL if one is set, otherwise the built-in endpoint. The logout button triggers the AJAX logout flow described in Logout & Single Logout. Buttons use the theme's standard wp-block-button__link wp-element-button classes.

[ps-sso-profile-button]

Displays a button linking to the Profile page URL — only when the user is logged in. Renders nothing for anonymous visitors.

[ps-sso-renewal-button]

For logged-in users: if the user's iMIS data flags them as renewal-eligible (sso-renewal-admin = true from the UsernameData IQA), displays a button to the Renewal page URL; otherwise displays the Renewal not available message. Renders nothing for anonymous visitors.

[ps-sso-renewal-banner]

Like the renewal button, but renders a banner (div.ps-renewal-banner) containing a link with the Renewal banner text. Shown only to logged-in, renewal-eligible users; renders nothing otherwise.

[ps-sso-name-display]

Displays Welcome, First Last for logged-in users (using the WordPress first/last name synced from iMIS). Renders nothing for anonymous visitors.

[ps-sso-user-field]

Displays a custom iMIS field synced to the logged-in user's meta by Custom iMIS Field Sync.

[ps-sso-user-field field="grad_year" label="Graduation year: " default="—"]
AttributeDescription
fieldRequired. The user meta key without the ps_sso_ prefix — shown in the Active mappings preview in settings. The built-ins imis_id (the user's iMIS ID) and renewal_admin (the renewal-eligibility flag) are also available.
labelOptional text rendered before the value.
defaultOptional text shown when the user is logged out or the field is empty/unavailable.

For security, only fields produced by Custom Field Sync (the configured map or the ps_sso_custom_user_fields filter) plus the two built-ins can be displayed — the shortcode cannot read arbitrary user meta.

[ps-sso-welcome]

A testing and troubleshooting aid. Displays the auth button plus the logged-in user's WordPress account details (username, roles, name, email, registration date). When Debug Mode is on, it also shows the cURL status, key configuration values, and the full log of the last SSO run. Requires a valid license.

[ps_sso_nested_links]

Displays a bulleted list of the current page's child pages, filtered by role-based access: only children the current visitor is allowed to see (unsecured, or secured with one of the visitor's roles) are listed.

[ps-sso-content-gate]

A gating marker for teaser previews. Place it inside any post or page that has role-based security assigned: everything before the marker is shown publicly as a teaser; everything after it is hidden and replaced with the authorization-required / access-denied message for visitors who lack access. If the shortcode is not present on a secured page, the entire content is gated. (Applies when the "show message" behavior is active, globally or per-page.)

The gate only affects the protected post's content. The theme's template output — sitewide footer, header, sidebars, and widgets — renders normally around the teaser and message.

[ps-sso-curlcheck]

Diagnostic: prints whether the required cURL PHP extension is installed and available.

Logout & Single Logout

The logout button ([ps-sso-auth-button], the nav-menu Logout item, or any element with the #ps-imis-sso-logout-button ID) triggers an AJAX call that ends the WordPress session, then redirects. Two modes, controlled by the Single Logout setting:

iMIS-initiated logout: when Single Logout is enabled, the plugin exposes a front-channel endpoint at {your-site}/?ps_sso_logout=1. Point the logout_target_url of your iMIS SingleLogout content record at this URL (the exact URL is displayed in the settings panel) so logging out of iMIS also ends the WordPress session. The endpoint logs the user out and redirects to the Logout URL, restricted to same-site destinations.

Cross-site cookie caveat: the WordPress→iMIS logout call only clears the iMIS session if the browser sends the iMIS cookie cross-site; third-party-cookie policies can block this. The most robust configuration is to point the Logout URL at the iMIS SingleLogout content record, letting the iMIS page end its own session (same-origin) and bounce back to the WordPress front-channel endpoint.

Role Synchronization

On every SSO login the plugin recalculates the user's WordPress roles from current iMIS data:

iMIS IQA Requirements

The plugin expects two IQA queries in iMIS (samples are shipped in the plugin's iMIS-iqa/ folder):

$/Philstack/UsernameData — returns the user's core properties:

ColumnUsed for
usernameiMIS username; committee lookups; iMIS Username matching mode
imis-idStored as imis_id user meta; uniqueness fallback for generated usernames
first-name, last-nameWordPress profile name; Full Name matching mode
emailWordPress email; Email matching mode
sso-roleMain WordPress role code (when member-type-as-role is enabled)
sso-role-descRole display name; recorded in the user description
companyAvailable to the login flow
sso-renewal-adminRenewal eligibility flag (true shows renewal button/banner)

Any additional columns you add to this IQA can be synced with Custom iMIS Field Sync — no code required.

$/Philstack/UsernameDataCommittees — returns committee assignments with properties CommitteeName, CommitteeProductCode, Position, TermStart, TermEnd. Only queried when Store iMIS Committee data as user meta is enabled.

Developer Hooks

Both hooks run on every SSO login, even when the settings-based Custom Field Sync is disabled.

Filter: ps_sso_custom_user_fields

Add, alter, or remove the custom fields stored as user meta during SSO login. Runs after the settings-based field map is applied, so you receive its output and can build computed/derived fields from any IQA column.

/**
 * @param array $custom_fields Unprefixed meta key => value. The ps_sso_ prefix
 *                             is added on write; keys are sanitized to [a-z0-9_].
 * @param array $imis_data     Every column returned by the UsernameData IQA
 *                             (Name => Value), mapped or not.
 * @param int   $user_id       The WordPress user ID being synced.
 * @return array
 */
add_filter('ps_sso_custom_user_fields', function ($custom_fields, $imis_data, $user_id) {
    // Derive a display badge from two raw IQA columns.
    if (!empty($imis_data['degree-program']) && !empty($imis_data['graduation-year'])) {
        $custom_fields['program_badge'] = $imis_data['degree-program'] . ' ’' . substr($imis_data['graduation-year'], -2);
    }
    return $custom_fields;
}, 10, 3);

Fields returned by the filter participate in the same lifecycle as mapped fields: they are written with the ps_sso_ prefix, tracked in the per-user index, displayable via [ps-sso-user-field], and cleaned up automatically when no longer returned.

Action: ps_sso_after_user_sync

Fires after an SSO login has fully synced the user (profile, roles, and meta) — on both the normal path and the exempt-role path. The API instance still holds a valid iMIS access token, so you can run additional IQA queries without re-authenticating.

/**
 * @param int      $user_id      The WordPress user ID.
 * @param array    $imis_data    Every column returned by the UsernameData IQA.
 * @param PsSsoApi $api_instance The authenticated API instance (access token
 *                               still valid for follow-up IQA queries).
 */
add_action('ps_sso_after_user_sync', function ($user_id, $imis_data, $api_instance) {
    // Example: record the member's company in a CRM sync queue.
    if (!empty($imis_data['company'])) {
        do_action('my_crm_queue_sync', $user_id, $imis_data['company']);
    }
}, 10, 3);

Typical uses: pushing data to other plugins or CRMs, running extra IQA queries, granting WooCommerce memberships, and custom audit logging.

Filter: ps_sso_auth_button_html

Customize the HTML markup rendered by the [ps-sso-auth-button] shortcode (the combined login/logout button). Runs every time the shortcode is rendered, whether the visitor is logged in or not.

/**
 * @param string $html               The generated button HTML (login markup when
 *                                    logged out, logout markup when logged in).
 * @param bool   $is_logged_in       Whether the current user is logged in.
 * @param string $login_url          The resolved login URL used when logged out
 *                                    (already includes any configured redirect_to).
 * @param string $login_button_text  Configured login button label.
 * @param string $logout_button_text Configured logout button label.
 * @return string
 */
add_filter('ps_sso_auth_button_html', function ($html, $is_logged_in, $login_url, $login_button_text, $logout_button_text) {
    if (!$is_logged_in) {
        return '<div class="ps-auth-button"><a href="' . esc_url($login_url) . '" class="my-theme-button">' . esc_html($login_button_text) . '</a></div>';
    }
    return $html;
}, 10, 5);

Note: the logout button's click behavior is bound by ID (#ps-imis-sso-logout-button) in assets/js/wp-imis-sso-logout-ajax.js. If you replace the logout markup, keep that id attribute on the clickable element or the AJAX logout won't fire.

Typical uses: swapping in theme-specific button classes/markup, adding icons, or wrapping the button in additional markup without editing plugin templates.

License Validation

The plugin validates its license with the Philstack licensing server using a fault-tolerant, cached system so temporary network issues (e.g. WAF blocks) never lock members out:

Debugging & Troubleshooting

  1. Enable Debug Mode in settings.
  2. Visit a page containing [ps-sso-welcome] — it shows the cURL status, key configuration values, and the complete log of the last SSO run (user matching, role decisions, redirect resolution, API results). The log is session-based and clears when the browser is closed.
  3. Check the PHP error log for the same events plus server-side detail (your hosting provider controls the log location; PHP logging may need to be enabled).
  4. Use [ps-sso-curlcheck] to confirm the required cURL extension is available.
  5. Verify custom field mappings on any user's profile screen (the iMIS Custom Fields panel) or via the Active mappings preview in settings.

Skip cURL cert validation exists for local development environments with self-signed certificates only — never enable it on a production site.