--- a/forms-bridge/addons/brevo/class-brevo-addon.php
+++ b/forms-bridge/addons/brevo/class-brevo-addon.php
@@ -138,42 +138,22 @@
* @return array
*/
public function get_endpoint_schema( $endpoint, $backend, $method = null ) {
- $bytes = random_bytes( 16 );
- $bytes[6] = chr( ord( $bytes[6] ) & 0x0f | 0x40 );
- $bytes[8] = chr( ord( $bytes[8] ) & 0x3f | 0x80 );
- $uuid = vsprintf( '%s%s-%s-%s-%s-%s%s%s', str_split( bin2hex( $bytes ), 4 ) );
+ if ( ! function_exists( 'yaml_parse' ) ) {
+ return array();
+ }
- $response = wp_remote_get(
- self::OAS_URL,
- array(
- 'headers' => array(
- 'Accept' => 'application/json',
- 'Host' => 'developers.brevo.com',
- 'Referer' => 'https://developers.brevo.com/reference/get_companies',
- 'Alt-Used' => 'developers.brevo.com',
- 'User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64; rv:144.0) Gecko/20100101 Firefox/144.0',
- 'X-Requested-With' => 'XMLHttpRequest',
- ),
- 'cookies' => array(
- 'anonymous_id' => $uuid,
- 'first_referrer' => 'https://app.brevo.com/',
- 'pscd' => 'get.brevo.com',
- 'readme_language' => 'shell',
- 'readme_library' => '{%22shell%22:%22curl%22}',
- ),
- )
- );
+ $response = wp_remote_get( self::OAS_URL );
if ( is_wp_error( $response ) ) {
return array();
}
- $data = json_decode( $response['body'], true );
+ $data = yaml_parse( $response['body'] );
if ( ! $data ) {
return array();
}
- $oa_explorer = new OpenAPI( $data['oasDefinition'] );
+ $oa_explorer = new OpenAPI( $data );
$method = strtolower( $method ?? 'post' );
$path = preg_replace( '/^/vd+/', '', $endpoint );
--- a/forms-bridge/addons/financoop/shortcodes.php
+++ b/forms-bridge/addons/financoop/shortcodes.php
@@ -51,10 +51,12 @@
$atts['currency'] = $atts['currency'] ?? '€';
try {
+ $campaign_id = absint( $atts['id'] );
+
$bridge = new Financoop_Form_Bridge(
array(
'name' => '__financoop-' . time(),
- 'endpoint' => "/api/campaign/{$atts['id']}",
+ 'endpoint' => "/api/campaign/{$campaign_id}",
'backend' => $atts['backend'],
'method' => 'GET',
),
@@ -82,18 +84,10 @@
?><article class="financoop-campaign wp-block-group">
<div class="financoop-campaign-header">
<div class="financoop-campaign-state">
- <?php
- echo esc_html(
- $campaign['state']
- );
- ?>
+ <?php echo esc_html( $campaign['state'] ); ?>
</div>
<h3 class="wp-block-heading">
- <?php
- echo esc_html(
- $campaign['name']
- );
- ?>
+ <?php echo esc_html( $campaign['name'] ); ?>
</h3>
<?php if ( $campaign['description'] ) : ?>
<p><?php echo wp_kses_post( $campaign['description'] ); ?></p>
@@ -162,114 +156,49 @@
$progress = round( min( 100, $progress ), 2 );
$goal = (int) $goal;
- if ( $goal === 0 ) {
+ if ( 0 === $goal ) {
return '';
}
ob_start();
?>
- <div class="financoop-campaign-progress" data-source="
- <?php
- echo esc_attr(
- $source
- );
- ?>
- ">
+ <div class="financoop-campaign-progress" data-source="<?php echo esc_attr( $source ); ?>">
<h4 class="wp-block-heading"><?php echo esc_html( $label ); ?></h4>
<p class="financoop-campaign-progress-item fraction">
- <span class="label">
- <?php
- echo esc_html(
- _x( 'Achieved', 'financoop campaign widget', 'forms-bridge' )
- );
- ?>
- : </span><span class="value">
- <?php
- echo number_format(
- $amount,
- 2,
- ',',
- '.'
- );
- ?>
- / <span class="value">
- <?php
- echo number_format(
- $goal,
- 2,
- ',',
- '.'
- );
- ?>
-<span class="unit"><?php echo esc_html( $currency ); ?></span></span>
+ <span class="label"><?php echo esc_html( _x( 'Achieved', 'financoop campaign widget', 'forms-bridge' ) ); ?>: </span>
+ <span class="value">
+ <?php echo number_format( $amount, 2, ',', '.' ); ?> / <?php echo number_format( $goal, 2, ',', '.' ); ?>
+ <span class="unit"><?php echo esc_html( $currency ); ?></span>
+ </span>
</p>
<p class="financoop-campaign-progress-item goal">
- <span class="label">
- <?php
- echo esc_html(
- _x( 'Goal', 'financoop campaign widget', 'forms-bridge' )
- );
- ?>
- : </span><span class="value">
- <?php
- echo number_format(
- $goal,
- 2,
- ',',
- '.'
- );
- ?>
- <span class="unit"><?php echo esc_html( $currency ); ?></span></span>
+ <span class="label"><?php echo esc_html( _x( 'Goal', 'financoop campaign widget', 'forms-bridge' ) ); ?>: </span>
+ <span class="value">
+ <?php echo number_format( $goal, 2, ',', '.' ); ?>
+ <span class="unit"><?php echo esc_html( $currency ); ?></span>
+ </span>
</p>
<p class="financoop-campaign-progress-item amount">
- <span class="label">
- <?php
- echo esc_html(
- _x( 'Received', 'financoop campaign widget', 'forms-bridge' )
- );
- ?>
- : </span><span class="value">
- <?php
- echo number_format(
- $amount,
- 2,
- ',',
- '.'
- );
- ?>
- <span class="unit"><?php echo esc_html( $currency ); ?></span></span>
+ <span class="label"><?php echo esc_html( _x( 'Received', 'financoop campaign widget', 'forms-bridge' ) ); ?>:</span>
+ <span class="value">
+ <?php echo number_format( $amount, 2, ',', '.' ); ?>
+ <span class="unit"><?php echo esc_html( $currency ); ?></span>
+ </span>
</p>
<p class="financoop-campaign-progress-item percentage">
- <span class="label">
- <?php
- echo esc_html(
- _x( 'Progress', 'financoop campaign widget', 'forms-bridge' )
- );
- ?>
- : </span><span class="value">
- <?php
- echo number_format(
- $progress,
- 2,
- ',',
- '.'
- );
- ?>
- <span class="unit">%</span></span>
+ <span class="label"><?php echo esc_html( _x( 'Progress', 'financoop campaign widget', 'forms-bridge' ) ); ?>: </span>
+ <span class="value">
+ <?php echo number_format( $progress, 2, ',', '.' ); ?>
+ <span class="unit">%</span>
+ </span>
</p>
<div class="financoop-campaign-progress-item progress-bar">
- <progress value='
- <?php
- echo intval(
- $progress
- );
- ?>
- ' max='100'><?php echo $progress; ?> %</progress>
+ <progress value='<?php echo intval( $progress ); ?>' max='100'><?php echo intval( $progress ); ?> %</progress>
</div>
</div>
<?php
@@ -376,7 +305,7 @@
array( 'id', 'backend', 'sources', 'currency' ),
function ( $handle, $attr ) use ( $atts ) {
if ( isset( $atts[ $attr ] ) ) {
- $value = implode( ',', (array) $atts[ $attr ] );
+ $value = esc_html( implode( ',', (array) $atts[ $attr ] ) );
$handle[] = "{$attr}='{$value}'";
}
--- a/forms-bridge/addons/holded/jobs/appointment-dates.php
+++ b/forms-bridge/addons/holded/jobs/appointment-dates.php
@@ -1,9 +1,24 @@
<?php
+/**
+ * Appointment dates Holded add-on job.
+ *
+ * @package formsbridge
+ */
if ( ! defined( 'ABSPATH' ) ) {
exit();
}
+/**
+ * Given a date string in format 'Y-m-d H:i:s' and a duration as a numeric value, it creates
+ * two payload fields:
+ * - startDate: The date value in timestamp format.
+ * - duration: As a float value with 1 as its fallback value.
+ *
+ * @param array $payload Bridge payload.
+ *
+ * @return array|WP_Error
+ */
function forms_bridge_holded_appointment_dates( $payload ) {
$datetime = DateTime::createFromFormat( 'Y-m-d H:i:s', $payload['date'] );
if ( $datetime === false ) {
--- a/forms-bridge/addons/listmonk/class-listmonk-form-bridge.php
+++ b/forms-bridge/addons/listmonk/class-listmonk-form-bridge.php
@@ -32,14 +32,11 @@
$error_response = $response->get_error_data()['response'] ?? null;
$code = $error_response['response']['code'] ?? null;
- if ( $code !== 409 ) {
+ if ( 409 !== $code ) {
return $response;
}
- if (
- ! isset( $payload['email'] ) ||
- $this->endpoint !== '/api/subscribers'
- ) {
+ if ( ! isset( $payload['email'] ) || '/api/subscribers' !== $this->endpoint ) {
return $response;
}
--- a/forms-bridge/addons/mailchimp/class-mailchimp-form-bridge.php
+++ b/forms-bridge/addons/mailchimp/class-mailchimp-form-bridge.php
@@ -54,13 +54,7 @@
}
if ( 'Member Exists' === $title ) {
- if (
- ! preg_match(
- '/(?<=lists/).+(?=/members)/',
- $this->endpoint,
- $matches
- )
- ) {
+ if ( ! preg_match( '/(?<=lists/).+(?=/members)/', $this->endpoint, $matches ) ) {
return $response;
}
@@ -84,17 +78,15 @@
return $response;
}
- $member_id =
- $search_response['data']['exact_matches']['members'][0]['id'] ?? null;
+ $member_id = $search_response['data']['exact_matches']['members'][0]['id'] ?? null;
if ( ! $member_id ) {
return $response;
}
$update_endpoint = "/3.0/lists/{$list_id}/members/{$member_id}";
- if (
- strstr( $this->endpoint, 'skip_merge_validation' ) !== false
- ) {
+
+ if ( false !== strstr( $this->endpoint, 'skip_merge_validation' ) ) {
$update_endpoint .= '?skip_merge_validation=true';
}
--- a/forms-bridge/addons/odoo/jobs/mailing-contact.php
+++ b/forms-bridge/addons/odoo/jobs/mailing-contact.php
@@ -1,10 +1,26 @@
<?php
+/**
+ * Update mailing contacts Odoo add-on job.
+ *
+ * @package formsbridge
+ */
if ( ! defined( 'ABSPATH' ) ) {
exit();
}
-function forms_brige_odoo_update_mailing_contact( $payload, $bridge ) {
+/**
+ * It performs a search request in order to find some mailing contact in Odoo by email. If found,
+ * then updates its list subscriptions and skip the submission. Otherwise returns the payload
+ * without changes and let the bridge to continue with the workflow.
+ *
+ * @param array $payload Bridge payload.
+ * @param Odoo_Form_Bridge $bridge Bridge object.
+ *
+ * @return array|null|WP_Error
+ */
+function forms_bridge_odoo_update_mailing_contact( $payload, $bridge ) {
+ // Patch the current bridge and dispatch a search request by email to mailing.contacts.
$response = $bridge
->patch(
array(
@@ -16,10 +32,13 @@
)
->submit( array( array( 'email', '=', $payload['email'] ) ) );
+ // If no contact is found the response is a 404 Not Found error.
if ( ! is_wp_error( $response ) ) {
$contact_id = $response['data']['result'][0];
$list_ids = $payload['list_ids'];
+ // Dispatch a `write` operation to update the `list_ids` field of the
+ // `mailing.contact` model.
$response = $bridge
->patch(
array(
@@ -31,10 +50,13 @@
)
->submit( array( $contact_id ), array( 'list_ids' => $list_ids ) );
+ // If Odoo returns an error, then return the error as the output of the job.
if ( is_wp_error( $response ) ) {
return $response;
}
+ // Otherwise, return an empty payload to abort the bridge submission. All work
+ // is done!
return;
}
@@ -47,7 +69,7 @@
'Search for a subscribed mailing contact, updates its subscriptions and skips if succeed',
'forms-bridge'
),
- 'method' => 'forms_brige_odoo_update_mailing_contact',
+ 'method' => 'forms_bridge_odoo_update_mailing_contact',
'input' => array(
array(
'name' => 'email',
--- a/forms-bridge/addons/zoho/class-zoho-form-bridge.php
+++ b/forms-bridge/addons/zoho/class-zoho-form-bridge.php
@@ -70,7 +70,17 @@
2
);
- $response = $this->backend()->$method(
+ $backend = $this->backend();
+
+ if ( ! $backend ) {
+ return new WP_Error(
+ 'invalid_backend',
+ 'The bridge does not have a valid backend',
+ (array) $this->data,
+ );
+ }
+
+ $response = $backend->$method(
$this->endpoint,
$payload,
array(),
--- a/forms-bridge/deps/http/includes/class-credential.php
+++ b/forms-bridge/deps/http/includes/class-credential.php
@@ -645,7 +645,7 @@
return;
}
- $access_token = $this->data['access_token'];
+ $access_token = $this->data['access_token'] ?? null;
if ( ! $access_token ) {
return;
}
--- a/forms-bridge/deps/plugin/class-setting.php
+++ b/forms-bridge/deps/plugin/class-setting.php
@@ -231,22 +231,24 @@
* Registers setting data on the database.
*
* @param array $data Setting data.
+ * @param bool $autoload Whether to load the option when WordPress starts up.
*
* @return bool Success status.
*/
- public function add( $data ) {
- return add_option( $this->option(), $data );
+ public function add( $data, $autoload = false ) {
+ return add_option( $this->option(), $data, '', $autoload );
}
/**
* Updates setting data on the database.
*
* @param array $data New setting data.
+ * @param bool $autoload Whether to load the option when WordPress starts up.
*
* @return bool Success status.
*/
- public function update( $data ) {
- return update_option( $this->option(), $data );
+ public function update( $data, $autoload = false ) {
+ return update_option( $this->option(), $data, $autoload );
}
/**
--- a/forms-bridge/forms-bridge.php
+++ b/forms-bridge/forms-bridge.php
@@ -9,7 +9,7 @@
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: forms-bridge
* Domain Path: /languages
- * Version: 4.2.5
+ * Version: 4.3.0
* Requires PHP: 8.0
* Requires at least: 6.7
*
--- a/forms-bridge/includes/class-addon.php
+++ b/forms-bridge/includes/class-addon.php
@@ -197,11 +197,7 @@
$registry = self::registry();
$addons = array();
foreach ( self::$addons as $name => $addon ) {
- $logo_path =
- FORMS_BRIDGE_ADDONS_DIR .
- '/' .
- $addon::NAME .
- '/assets/logo.png';
+ $logo_path = FORMS_BRIDGE_ADDONS_DIR . '/' . $addon::NAME . '/assets/logo.png';
if ( is_file( $logo_path ) && is_readable( $logo_path ) ) {
$logo = plugin_dir_url( $logo_path ) . 'logo.png';
--- a/forms-bridge/includes/class-form-bridge.php
+++ b/forms-bridge/includes/class-form-bridge.php
@@ -194,21 +194,25 @@
'default' => array(),
),
'is_valid' => array(
- 'description' => __(
- 'Validation result of the bridge setting',
- 'forms-bridge'
- ),
+ 'description' => __( 'Validation result of the bridge setting', 'forms-bridge' ),
'type' => 'boolean',
'default' => true,
),
'enabled' => array(
- 'description' => __(
- 'Boolean flag to enable/disable a bridge',
- 'forms-bridge'
- ),
+ 'description' => __( 'Boolean flag to enable/disable a bridge', 'forms-bridge' ),
'type' => 'boolean',
'default' => true,
),
+ 'allow_failure' => array(
+ 'description' => __( 'Whether an error on bridge submission should stop the submission loop or not', 'forms-bridge' ),
+ 'type' => 'boolean',
+ 'default' => true,
+ ),
+ 'order' => array(
+ 'description' => __( 'Order in which the bridge should be submitted in the submission loop', 'forms-bridge' ),
+ 'type' => 'integer',
+ 'default' => -1,
+ ),
),
'required' => array(
'name',
@@ -221,6 +225,8 @@
'workflow',
'is_valid',
'enabled',
+ 'allow_failure',
+ 'order',
),
'additionalProperties' => false,
);
@@ -448,7 +454,11 @@
$backend = $this->backend();
if ( ! $backend ) {
- return new WP_Error( 'invalid_bridge' );
+ return new WP_Error(
+ 'invalid_backend',
+ 'The bridge does not have a valid backend',
+ (array) $this->data,
+ );
}
$method = $this->method;
--- a/forms-bridge/includes/class-forms-bridge.php
+++ b/forms-bridge/includes/class-forms-bridge.php
@@ -283,7 +283,23 @@
return;
}
- foreach ( $bridges as $bridge ) {
+ usort(
+ $bridges,
+ function ( $a, $b ) {
+ if ( 0 > $a->order ) {
+ return 1;
+ } elseif ( 0 > $b->order ) {
+ return -1;
+ }
+
+ return $a->order - $b->order;
+ }
+ );
+
+ $l = count( $bridges );
+ for ( $i = 0; $i < $l; ++$i ) {
+ $bridge = $bridges[ $i ];
+
if ( ! $bridge->enabled ) {
Logger::log(
'Skip submission for disabled bridge ' . $bridge->name
@@ -436,6 +452,15 @@
$payload ?? $submission,
$attachments ?? array()
);
+
+ if (
+ false === $bridge->allow_failure
+ && count( $bridges ) > 1
+ && $i < count( $bridges ) - 1
+ ) {
+ Logger::log( 'Early exit from the submission loop due to an error', Logger::ERROR );
+ break;
+ }
} finally {
self::$current_bridge = null;
}
--- a/forms-bridge/includes/class-integration.php
+++ b/forms-bridge/includes/class-integration.php
@@ -197,10 +197,19 @@
$registry = self::registry();
$integrations = array();
foreach ( self::$integrations as $name => $integration ) {
+ $logo_path = FORMS_BRIDGE_INTEGRATIONS_DIR . '/' . $integration::NAME . '/assets/logo.png';
+
+ if ( is_file( $logo_path ) && is_readable( $logo_path ) ) {
+ $logo = plugin_dir_url( $logo_path ) . 'logo.png';
+ } else {
+ $logo = '';
+ }
+
$integrations[ $name ] = array(
'name' => $name,
'title' => $integration::TITLE,
'enabled' => $registry[ $name ] ?? false,
+ 'logo' => $logo,
);
}