'adfoin',
'show_status' => true,
'enable_test' => false,
'modal_title' => sprintf( __( 'Connect %s', 'advanced-form-integration' ), $title ),
'submit_text' => __( 'Save & Authorize', 'advanced-form-integration' ),
) );
$nonce = wp_create_nonce( 'advanced-form-integration' );
?>
$platform,
'fields' => $fields,
'nonce' => $nonce,
'showStatus' => (bool) $config['show_status'],
'enableTest' => (bool) $config['enable_test'],
'i18n' => array(
'save' => $config['submit_text'],
'update' => __( 'Update & Authorize', 'advanced-form-integration' ),
'confirmDelete' => __( 'Are you sure you want to delete this account?', 'advanced-form-integration' ),
'deleteFailed' => __( 'Failed to delete account.', 'advanced-form-integration' ),
'saveFailed' => __( 'Failed to save account.', 'advanced-form-integration' ),
'error' => __( 'An error occurred. Please try again.', 'advanced-form-integration' ),
'loading' => __( 'Loading...', 'advanced-form-integration' ),
'untitled' => __( 'Untitled', 'advanced-form-integration' ),
'connected' => __( 'Connected', 'advanced-form-integration' ),
'notConnected' => __( 'Not Connected', 'advanced-form-integration' ),
'connectionBroken' => __( 'Connection broken — Reconnect', 'advanced-form-integration' ),
'noAccounts' => __( 'No accounts found. Click "Add Account" to get started.', 'advanced-form-integration' ),
'authFailed' => __( 'Authorization failed:', 'advanced-form-integration' ),
'edit' => __( 'Edit', 'advanced-form-integration' ),
'delete' => __( 'Delete', 'advanced-form-integration' ),
'test' => __( 'Test connection', 'advanced-form-integration' ),
'testing' => __( 'Testing…', 'advanced-form-integration' ),
'testOk' => __( 'Connection OK', 'advanced-form-integration' ),
'testFailed' => __( 'Connection test failed:', 'advanced-form-integration' ),
),
);
?>
_credentials`
// option, which split accounts away from ADFOIN_Account_Manager and
// also bypassed the `adfoin_get_credentials` filter. Routing through
// adfoin_read_credentials() fixes both.
$credentials = function_exists( 'adfoin_read_credentials' )
? adfoin_read_credentials( $platform )
: array();
return is_array( $credentials ) ? $credentials : array();
}
/**
* Get a specific credential by ID.
*
* @param string $platform Platform slug.
* @param string $id Credential ID.
* @return array|false Credential data or false if not found.
*/
public static function get_credentials_by_id( $platform, $id ) {
$credentials = self::get_credentials( $platform );
foreach ( $credentials as $credential ) {
if ( isset( $credential['id'] ) && $credential['id'] === $id ) {
return $credential;
}
}
return false;
}
/**
* Save credentials for a platform.
*
* @param string $platform Platform slug.
* @param array $new_credentials New credential data.
* @return bool True on success, false on failure.
*/
public static function save_credentials( $platform, $new_credentials ) {
$credentials = self::get_credentials( $platform );
// Check if this is a delete operation
if ( isset( $_POST['delete_index'] ) ) {
$delete_index = intval( wp_unslash( $_POST['delete_index'] ) );
if ( isset( $credentials[ $delete_index ] ) ) {
unset( $credentials[ $delete_index ] );
$credentials = array_values( $credentials ); // Re-index array
adfoin_save_credentials( $platform, $credentials );
return true;
}
return false;
}
// Generate ID if not present
if ( ! isset( $new_credentials['id'] ) ) {
$new_credentials['id'] = uniqid( 'cred_' );
}
// Check if updating existing credential
$updated = false;
foreach ( $credentials as $index => $credential ) {
if ( isset( $credential['id'] ) && $credential['id'] === $new_credentials['id'] ) {
$credentials[ $index ] = array_merge( $credential, $new_credentials );
$updated = true;
break;
}
}
// Add new credential if not updating
if ( ! $updated ) {
$credentials[] = $new_credentials;
}
// Persist to the canonical store (see get_credentials() for rationale).
adfoin_save_credentials( $platform, $credentials );
return true;
}
/**
* Update specific credentials by ID.
*
* @param string $platform Platform slug.
* @param string $id Credential ID.
* @param array $updated_data Updated credential data.
* @return bool True on success, false on failure.
*/
public static function update_credentials( $platform, $id, $updated_data ) {
$credentials = self::get_credentials( $platform );
foreach ( $credentials as $index => $credential ) {
if ( isset( $credential['id'] ) && $credential['id'] === $id ) {
$credentials[ $index ] = array_merge( $credential, $updated_data );
// Persist to the canonical store (see get_credentials()).
adfoin_save_credentials( $platform, $credentials );
return true;
}
}
return false;
}
/**
* Outputs the HTML/JS to close the OAuth popup and notify the parent window.
*
* @param bool $success Whether the authorization was successful.
* @param string $message Optional message to send back.
*/
public static function handle_callback_close_popup( $success = true, $message = '' ) {
$status = $success ? 'success' : 'error';
$message_json = wp_json_encode( (string) $message );
$status_json = wp_json_encode( $status );
if ( ! headers_sent() ) {
header( 'Content-Type: text/html; charset=utf-8' );
}
// We use localStorage (not postMessage) for popup→parent
// communication. Reason: `window.opener.postMessage` requires
// `window.opener` to be alive, but it gets severed in many real-world
// setups — Cross-Origin-Opener-Policy: same-origin, popup blockers,
// some security plugins, and browser tracking-protection all strip
// the opener relationship when the popup navigates cross-origin to
// the OAuth provider. Result: the parent never received the
// success/error notification, the popup auto-closed silently, and
// the user saw "OAuth doesn't work" with no feedback.
//
// localStorage events fire across every same-origin tab regardless
// of opener state, so the parent's `storage` listener always picks
// up the result.
echo '
Authorization ' . esc_html( ucfirst( $status ) ) . '
' . ( $success ? 'Authorization Successful!' : 'Authorization Failed' ) . '
' . esc_html( $message ) . '
This window will close automatically...
';
exit;
}
}