get_error_code() ) { Send4_Minimum_Version::refresh_if_stale(); } } /** * Push the inventory if it has changed, or if the last push is stale. * * @param bool $force Push even when nothing changed. * @return true|WP_Error|null True on a push, WP_Error on failure, null when skipped. */ public static function maybe_push( $force = false ) { if ( ! Send4_Settings::has_credentials() ) { return null; } $descriptors = Send4_Form_Descriptors::build(); $environment = Send4_Environment::report(); $hash = self::fingerprint( $descriptors, $environment ); if ( ! $force && ! self::is_due( $hash ) ) { return null; } $result = ( new Send4_Api_Client() )->report_forms( $descriptors, $environment ); if ( is_wp_error( $result ) ) { // The hash is deliberately NOT stored: leaving it stale is what // makes the next save or the daily sweep try again. Send4_Logger::log( 'warning', 'Could not report this site\'s forms to Send4.', array( 'error' => $result->get_error_message(), 'code' => $result->get_error_code(), ) ); return $result; } update_option( self::HASH_OPTION, $hash, false ); update_option( self::AT_OPTION, time(), false ); return true; } /** * What the stored hash is compared with: the inventory and what the site runs. * * The environment is in it so that a plugin, WordPress or PHP update is * reported at the next sync, not only once the forms happen to change. * * @param array $descriptors Descriptors from Send4_Form_Descriptors::build(). * @param array $environment From Send4_Environment::report(). * @return string */ public static function fingerprint( array $descriptors, array $environment ) { return md5( Send4_Form_Descriptors::hash( $descriptors ) . '|' . (string) wp_json_encode( $environment ) ); } /** * Whether a push is warranted. * * @param string $hash Fingerprint of the current inventory. * @return bool */ private static function is_due( $hash ) { if ( get_option( self::HASH_OPTION, '' ) !== $hash ) { return true; } $last = (int) get_option( self::AT_OPTION, 0 ); return ( time() - $last ) >= self::MAX_AGE; } /** * When the inventory was last accepted by Send4, for the admin screens. * * @return int Unix timestamp, 0 when never. */ public static function last_synced_at() { return (int) get_option( self::AT_OPTION, 0 ); } /** * Forget the sync state, so the next push is unconditional. * * Called on disconnect: the next connection may be a different workspace, * which has never been told anything about this site's forms. * * @return void */ public static function forget() { delete_option( self::HASH_OPTION ); delete_option( self::AT_OPTION ); } }