Bypass all resource restrictions, passwords, and keys? Read here!
Decryption key:
WooCommerce RedSys Gateway v32.2.0
2026.10.14 - version 32.2.0
* DEV: The package published on WooCommerce.com no longer includes the license and update client used by copies bought at plugins.joseconti.com (it was never loaded there). The plugin loads it only when the file is present.
* DEV: Added phpstan.neon (bundled third-party libraries excluded, baseline of existing findings) so static analysis reports only new problems.
* FIX: InSite: the "Language Gateway" setting was ignored, so the card fields (placeholders and button) were always shown in Spanish. The chosen language is now sent to Redsys in the classic checkout and in the Checkout Block.
* NEW: Filter redsys_insite_form_language, to choose the language of the InSite card form from code (for example, one per site language).
* FIX: Updating with UCP enabled ended in a "critical error" (Call to a member function using_index_permalinks() on null) on the first page load after the update. The public UCP discovery file is now rewritten once WordPress has finished loading.
* FIX: Expired saved cards: the scheduled tasks that warn the customer and remove expired cards failed with a database error ("You have an error in your SQL syntax") and never did anything. They now work, remove cards that expired in an earlier year too, and only touch cards saved by this plugin.
* FIX: Customers with more than 10 saved cards: subscription renewals and the Immediate Redsys Charge could use an older card instead of the newest one, a card already saved could be saved again, and the classic checkout did not list the newest cards. The plugin now reads all the Redsys cards of the customer for its own decisions.
* NEW: Filter redsys_customer_tokens_limit, to change how many saved cards of a customer the plugin reads (500 by default).
* FIX: License: when the license server refused the activation, the settings page only said "Your settings have been saved.". The error returned by the server is now shown, and a refused key is no longer displayed as "License is Active".
* FIX: License: saving Redsys Advanced with the license already active sent it to be activated again on every save. An active license is no longer re-sent.
* FIX: Immediate Redsys Charge (and any charge with a saved card): when Redsys rejected the charge at its first step, the order stayed pending with no explanation. The reason and the Redsys error code are now written in an order note.
* FIX: InSite in the block checkout: a card saved for Pay with One Click after a 3DS challenge was stored as a subscription card. It is now stored with the type it was requested with.
* FIX: InSite in the block checkout: the pay button always read "Pagar". It now shows the translated "Pay" label of the site language.
* FIX: InSite in the block checkout: on a server without the PHP SOAP extension the payment ended in a "critical error". The customer now gets a message asking to choose another payment method, and the cause is written to the InSite log.
* FIX: Classic checkout: with Bizum and Bizum Checkout both in test mode, the test-mode warning was shown twice.
* FIX: One-click purchase from the product page: the shipping options showed "€" instead of the currency symbol.
* FIX: Confirming a pre-authorisation wrote the order status note twice, and moved the order to Completed even when another status was configured for confirmed pre-authorisations.
* FIX: Block checkout: when Bizum Checkout was denied the customer was sent back to the checkout with no message. The error is now shown, as it already was in the classic checkout.
* FIX: Block checkout: an order paid with Bizum (or another gateway of this plugin that uses a payment page) by a customer with a saved card was recorded as paid by card. The order keeps the payment method it was placed with.
* FIX: Bizum, Bizum Checkout, Google Pay, Apple Pay, Direct Debit and PayGold in test mode: with the test key configured and the real key field empty, the payment was authorised by Redsys but the order stayed pending, because the notification was rejected. In test mode the notification is now verified with the test key.
* FIX: Block checkout: paying with a saved card (Pay with One Click) was rejected by Redsys with error SIS0574 (browserUserAgent not indicated). The 3DS browser data is now attached to the order in the block checkout too.
* FIX: Apple Pay: the debug log now shows the parameters actually sent to Redsys, read back from the signed request. Before, its lines were written separately and could differ from the request: the subscription parameters were sent but not logged, and the Apple MerchantID line was logged even when it was not sent.
* FIX: My account > Payment methods: the "Type" column printed PHP warnings (Undefined array key "delete", Undefined variable $token_type_name) on cards or accounts saved by other gateways, for example PayPal. It now describes only the cards saved by this plugin and shows "--" for any other saved method.
* FIX: Bizum Checkout: the waiting page shown while the payment is confirmed loaded jQuery from ajax.googleapis.com. It now uses the copy WordPress ships, so the page makes no request to a third party.
* FIX: readme.txt declared a malformed license line and "Tested up to: 7.0" while the plugin header said 7.1. Both files now say GPL-3.0-or-later and 7.1.
* FIX: ACP (off by default): with ACP on, WordPress could log "Translation loading for the woocommerce domain was triggered too early" when the hourly ACP clean-up was first scheduled. It is now scheduled on init.
* FIX: Duplicated scheduled actions left by earlier versions are now removed on their own: the paired redsys_acp_process_webhooks / redsys_ucp_process_webhooks workers, a redsys_check_emails_cron with no group, and repeated daily clean-ups. Since 32.1.0 no new ones were created, but existing ones stayed.
* FIX: The plugin's text domain is now its slug, woocommerce-gateway-redsys (it was woocommerce-redsys), in every string, in the bundled translation files and in the Checkout Blocks scripts. Custom translation files saved under the old name in wp-content/languages/plugins or by Loco Translate keep working. Translations stored in the database by a multilingual plugin (WPML String Translation, Polylang) and custom code that filters gettext by the old domain need the new name.
* FIX: Three strings used WooCommerce's text domain and four order-status counters had none; one of them (the cancelled-order plain e-mail) could never be translated. They now use the plugin's.
* FIX: Subscription renewals sent no description to Redsys, so the operation showed an empty description in the TPV (first payments were fine). Renewals and invoice charges of the redirect gateway, and renewals of InSite, now send the description chosen in the gateway settings, as they did before renewals moved to the REST API.
* FIX: Paying at checkout with a saved card (redirect gateway) always sent "Order N" as the description, whatever the gateway setting said. It now follows the setting.
* FIX (security): UCP MCP (off by default): an agent could ask lookup_catalog for any number of products and get an answer of any size. A lookup now takes at most 50 products and no tool returns more than 1 MB (both adjustable with filters).
* FIX (security): UCP MCP (off by default) kept no record of what agents did. Every tool call is now written to an audit log (which agent client, which tool, the result and its duration; arguments only as a fingerprint and a masked summary), kept for 90 days.
* FIX (security): UCP MCP (off by default) had no request limit. Each address also has a budget checked before authentication (300 calls per minute by default), and a batch request carries at most 20 calls.
* FIX (security): UCP MCP (off by default) had no request limit. Each agent client now has a budget of 60 tool calls per minute, 600 per hour and 5000 per day (the same as A2A, adjustable with the redsys_ucp_mcp_rate_limits filter); past it, calls get a 429 error.
* BEHAVIOUR CHANGE (security): UCP MCP (off by default): tool arguments are now checked against each tool's published input schema before the tool runs; calls that do not match (for example without meta.ucp-agent.profile) get a JSON-RPC -32602 error listing what is wrong.
* FIX: ACP (off by default): the public ACP document announced a limit of 60 requests per minute that was never applied. The announcement is removed.
* BEHAVIOUR CHANGE (security): UCP (off by default): Dynamic Client Registration - any AI agent creating its own OAuth client in the store - is now off by default, and switched off once on update where it was only on by the old default. If your agents register themselves, turn "Allow Dynamic Client Registration" back on in the UCP settings.
* FIX (security): ACP (off by default): its "HTTPS required" check believed an X-Forwarded-Proto or X-Forwarded-SSL header from anyone. These headers now count only from the proxies listed in the "Trusted proxies" setting (A2A > Status). HEADS-UP: behind a proxy or CDN that ends HTTPS, list its addresses there after updating.
* FIX (security): UCP OAuth (off by default): authorization codes were stored in the database in plain text while tokens were hashed. They are hashed now too.
* BEHAVIOUR CHANGE (security): UCP OAuth (off by default) now accepts only the S256 PKCE method, as the UCP profile requires; "plain" is refused. A developer who needs it can return true from the redsys_ucp_allow_pkce_plain filter.
* BEHAVIOUR CHANGE (security): UCP OAuth (off by default): the token introspection endpoint answered anyone. It now requires the calling client's credentials (client_id and client_secret) and only reports on that client's own tokens, as RFC 7662 requires.
* FIX (security): A2A (off by default): after the card authentication step, the shopper could be sent to any address the agent had given, including plain http or internal addresses. Only https addresses on public hosts are used now; otherwise the shopper lands on the order page. The redsys_a2a_sca_return_url filter can narrow this further.
* FIX (security): UCP MCP (off by default): when a tool failed inside the store, the agent received the internal error text (which can include server paths). It now receives a correlation id; the detail is written to the plugin log.
* BEHAVIOUR CHANGE (security): UCP and A2A (off by default) no longer accept the access token in the URL (?access_token=), where it ends up in server logs; send it in the Authorization header. A developer who needs the old behaviour can return true from the redsys_allow_bearer_in_query_string filter.
* FIX (security): UCP OAuth (off by default): two token requests sent at the same time with the same authorization code could both succeed. The code is now redeemed atomically; only one request gets tokens.
* FIX (security): Inespay: after checking the notification's signature, the plugin still let unsigned fields of the request fill in values the signed data did not carry (such as the payment id). Only the signed data is used now.
* FIX (security): Apple Pay and Google Pay marked the order paid without checking that the amount Redsys charged matched the order total, as card and Bizum payments already do. A different amount now puts the order on hold with a note, for you to review.
* FIX: UCP OAuth (off by default): two refreshes sent at the same time with the same refresh token could both obtain a new token pair. The refresh token is now spent atomically; the second request gets invalid_grant.
* FIX (security): A2A (off by default): when an operation failed inside the store, the agent received the internal error text (which can include server paths). It now receives a generic message with a correlation id; the detail is written to the plugin log.
* FIX: A2A (off by default): the maximum amount set for create_payment and tokenize_card was not applied. Amounts above it are now refused before any order is created.
* FIX (security): Redsys Manager app: an employee whose WordPress role was lowered to customer or subscriber kept their app profile, and with it access to orders and customer data. Their app profile is now removed when the role changes.
* FIX (security): The public discovery documents for AI agents (UCP /.well-known/ucp and the ACP well-known document) published the WordPress administrator's e-mail address. They now publish the address set in the new "Support e-mail for AI agents" setting, or none.
* FIX (security): A2A (off by default): the refund amount above which a store administrator must confirm ("sensitive threshold") was checked refund by refund, so splitting a refund avoided it. It now adds up what the same client refunded on the same order in the last 24 hours. HEADS-UP: a batch of small refunds on one order may now wait for your confirmation.
* FIX (security): A2A (off by default): a client's IP allow-list could be passed by sending an X-Forwarded-For header with an allowed address. The plugin now checks the connection's own address and believes X-Forwarded-For only from the proxies listed in the new "Trusted proxies" setting (A2A > Status). HEADS-UP: if your site sits behind a CDN or load balancer and an A2A client has an IP allow-list, add the CDN's addresses to that setting after updating, or the client will be refused.
* FIX (security): A2A (off by default): task streams ignored the client's rate limit, so one client could open enough of them to tie up the shop's PHP workers. Each stream now counts against the limit and a client can hold at most five at once.
* FIX (security): Switching A2A off in the settings did not stop clients that were already set up. With A2A off, its JSON-RPC endpoint and task streams now answer 503 and no push notification is sent.
* FIX (security): The Redsys bulk actions in the orders list (immediate charge, bulk refund, approve pre-authorization) now need the same permission as their single-order versions (manage WooCommerce) and only run while their setting is on.
* FIX (security): A2A (off by default): the push address an agent gives for task notifications could make the shop call its own server or internal network, even over plain http. It must now be https on port 443 of a public host, and notifications use WordPress's safe HTTP transport.
* FIX (security): ACP webhooks (off by default): a provider could register a webhook pointing at the shop's own server or internal network. A webhook URL must now be port 443 on a public host (a filter allows otherwise for development), webhooks registered earlier that break the rule are no longer called, and deliveries use WordPress's safe HTTP transport.
* FIX (security): UCP (off by default): the platform profile address an agent sends in its UCP-Agent header could make the shop call its own server or internal network. Only https addresses on port 443 of public hosts are fetched now, through WordPress's safe HTTP transport.
* FIX (security): UCP webhooks (off by default): a client could register a webhook pointing at the shop's own server or internal network, and a read-only token was enough. A webhook URL must now be https on port 443 to a public host, registering or deleting one needs the checkout write scope, webhooks registered earlier that break the rule are no longer called, and deliveries use WordPress's safe HTTP transport.
* FIX (security): UCP, MCP and A2A (off by default) accepted an OAuth refresh token as if it were an access token. Only access tokens open those routes now.
* FIX (security): Agentic checkouts (UCP and ACP, off by default): an AI agent could put on an order products the shop does not sell - drafts, private or out-of-stock products, variable or grouped parents. The order is now refused (422) and names the products.
* FIX (security): The plugin's "View details" window read the update server's answer with a function that can build PHP objects. It now reads that answer as plain data only.
* FIX (security): The checkout's 3-D Secure browser-data request could write that data onto any order number. It now writes only onto the visitor's own order and otherwise keeps it in their session.
* FIX (security): Agentic checkout (ACP, off by default): an order created by an AI agent was attached to any registered customer whose e-mail the agent sent. It now stays a guest order; stores that want the old behaviour can return true from the redsys_acp_link_order_to_customer_by_email filter.
* FIX: A failed or late payment notification (for example the "denied" result of an earlier attempt arriving after the order was paid) could cancel an order that was already paid - in Bizum and in the other Redsys payment methods. A paid order is now never cancelled by a notification; a note records what Redsys sent.
* FIX (security): One-click buy took the shipping cost and name from the browser, so a logged-in customer could pay less shipping (or none). The shipping is now recalculated by the store and must be one of the options the store offers; a product that needs shipping cannot be bought without it.
* FIX (security): Agentic catalogues (UCP catalog and ACP product feed, both off by default) listed draft and "Private products", and the UCP single-product lookup returned unpublished products. Agents now only see published products that are not private. A variation of a private product is private too.
* FIX (security): The Users-screen bulk actions "Request Redsys card" and PayGold did not check that the request came from that screen, so a page on another site could make a logged-in administrator send card-request e-mails (or PayGold operations) to arbitrary users. They now require the Users screen's security token and shop-manager rights. The PayGold handler also stops interfering with other plugins' bulk actions on that screen.
* FIX (security): Agentic checkout (ACP): revoking an access token did not clear its cached approval, so a revoked token kept working for up to five minutes. Revoking now takes effect immediately.
* FIX (security): Agentic checkout (ACP, off by default): access tokens generated as "Read only" were accepted for creating, changing and cancelling orders and managing webhooks. They are now read-only.
* FIX (security): Agentic checkout (ACP, off by default): a checkout session could be read, changed, completed or cancelled by any client that knew its id. Sessions now answer only the AI provider that created them.
* FIX (security): Agentic checkout (ACP, off by default): a client using a WooCommerce REST API key could claim to be another AI provider and read, delete or add that provider's webhooks. The provider is now taken only from the credential; bearer tokens registered in WooCommerce's agentic settings now resolve to their provider (so ACP webhooks work as intended), and a session with no provider no longer sends its events to every provider's webhooks.
* FIX (security): Agentic checkout (UCP, off by default): a checkout session could be read, changed, completed or cancelled by any client that knew its id, and the order endpoints skipped the owner check for a token with no user. Sessions now answer only the client and customer that created them, and a token with no user is refused.
* FIX (security): Agentic checkout (ACP, off by default): an agent could change the address and total of an order that was already paid, cancel it without a refund, or send it to the payment page again. Those requests are now refused (409) once the order is no longer open; a preauthorized order is voided from the store admin, not by an agent.
* FIX (security): Agentic checkout (UCP, off by default): an agent could still change the items and total of a checkout session after its order was paid, or cancel the paid order without a refund. A session whose order is paid, cancelled or failed can no longer be changed or cancelled.
* FIX: "Private products" (off by default) did not work: products marked private were only removed from the shop listing and could still be viewed and bought by anyone, and the list of allowed users was saved empty. A private product is now hidden (product page, Blocks/Store API) and cannot be bought by anyone outside its list; shop managers always see it. IMPORTANT if you use this option: open each private product and select its allowed users again - earlier versions lost those lists. A notice on the product screens reminds you.
* FIX (security): InSite on the Blocks checkout could attach another shopper's in-progress Redsys payment number to a new order, so that shopper's payment confirmation could land on the wrong order. A number that already belongs to another order is no longer attached.
* FIX (security): The "add payment method" redirect link answered anyone, and when given an order number it rewrote that order's terminal and key settings with the defaults (breaking later refunds on multi-terminal stores). It now only answers the logged-in customer who started adding the card, and never writes order data.
* FIX (security): The card payment notification set its "already processing" marker before checking the signature, so a forged request could make the store ignore Redsys's genuine notification for a minute and leave a paid order pending. The marker is now set only after the signature is valid.
* FIX (security): Manager app (off by default): a staff profile allowed to edit customers could also edit an administrator's account, including the e-mail, which is enough to take it over with a password reset. The app's customer screens now only load and edit customer accounts, never staff.
* FIX (security): Licence activation and update checks talked to plugins.joseconti.com without verifying its TLS certificate, and trusted whatever the reply said about which plugin to update and where to download it. TLS is now always verified, the update offered is always for this plugin, and the download must come over https from the licence server itself.
* FIX (security): E-mail payment fallback (IMAP/Gmail, off by default): an e-mail whose sender merely contained the Redsys address could mark a pending order as paid, and so could a real Redsys e-mail about a denied payment. Now the sender must be exactly the address set in the settings, and the e-mail must show an approved payment for the order's amount and merchant code; otherwise the order is left as it was and gets a note. If you entered only part of the Redsys address (or only the domain) in those settings, enter the full address.
* FIX (security): Removed an unused InSite REST address (woocommerce-redsys/v1/save_order_data) that let a request carrying only a matching Referer header change the Redsys order number stored on any order, which refunds rely on. The Blocks checkout has not used it since 31.0.4.
* FIX (security): Agentic checkout (UCP, off by default): an order created by an AI agent was attached to whichever registered customer owned the e-mail the agent sent, which also put that customer's saved cards within reach. The order now belongs to the customer who authorised the agent, and never to someone because of an e-mail address.
* FIX (security): Apple Pay express stored a temporary marker under a name taken from the browser, and that name could match the markers the plugin reads to confirm payments. Wallet markers (Apple Pay and Google Pay) now live under their own hashed names.
* FIX (security): Completes the saved-card fix above for the redirect payment page. The card chosen at checkout was also carried into the signed Redsys payment form without checking whose card it was. The form now uses a saved card only if it belongs to the customer paying; otherwise it asks for a new card (a new subscription card when the order has a subscription).
* FIX (security): Each order keeps the Redsys key it was paid with, so refunds and renewals keep working when several terminals are in use. WooCommerce's REST API returned that key to any integration with a read-only API key. It is no longer included in order or subscription REST responses; it is still stored and used exactly as before.
* FIX (security): With "Show the Redsys page inside the store" (iframe mode), and for every Bizum Checkout order, the return links printed an order's cancel and order-received addresses, with its private key, to anyone who asked, for as long as the store kept a marker that never expired. They now answer only the buyer who owns the order (the return links sent to Redsys carry the order key for that), and the marker expires after a day.
* FIX (security): A notification-endpoint link used by the retired 3-D Secure method step sent any visitor to the payment page of the order number in the link, including its private order key. It now only sends the buyer who owns the order there (card and InSite).
* FIX (security): The extra fields that Apple Pay and Google Pay express buttons ask for (NIF/DNI and similar) stored whatever field names the request carried, on the order and on the customer's account. They now store only the fields your store defines, and never the plugin's internal data. Shops that show express buttons should update.
* FIX (security): A saved card could be charged by someone it did not belong to. The card is identified in the checkout request by a row number, and the plugin did not check whose card it was, so a crafted request could charge another customer's saved card without the bank asking that customer to confirm anything. Every charge with a saved card now checks that the card belongs to the customer who is paying, and refuses the payment otherwise; a card id that does not exist no longer causes a fatal error. Shops that offer saved cards should update. Reported privately, with the cause already located, by a shop that chose to tell us first and publish nothing - thank you.
* FIX: In test mode, "Show to this users" limits a gateway to the users you pick. The Blocks checkout ignored it and showed the gateway to every visitor, guests included; the order was then rejected, so the customer saw a payment method that failed when pressed. Every gateway now applies the list in the Blocks checkout as well as the classic one. A developer filter, redsys_gateway_shown_to_user, can adjust the decision. Reported with the cause already located - thank you.
* FIX: Apple Pay and Google Pay (checkout) had the "Show to this users" field but never applied it, in any checkout. They now do.
* FIX: With Inespay, a user on the "Show to this users" list could still be hidden, because the saved list was compared the wrong way. Listed users now see it.
* FIX: With "Pay with One Click" from the product page active, the plugin added two headings - "Terms and Conditions" and "Select Shipping Method" - to every product page, even when nobody had opened those windows, which cluttered the page structure that search engines and accessibility tools read. Those windows are now built only when they are actually opened, and their title is no longer a heading: it names the window for screen readers instead, which the windows for terms and shipping did not do before. Nothing changes in what the customer sees. Reported by a shop that found it in its heading audit - thank you.
* FIX: The script and the styles of "Pay with One Click" from the product page loaded on every product page, including where the button never appears because the option is off or the visitor is not logged in. They now load only where the button does.
* NEW: The plugin license is now managed in WooCommerce > Settings > Redsys Advanced > General, at the top of the page, and no longer has its own entry in the WooCommerce menu. The license key, how it is activated and where it is stored do not change, and the old address still works: it takes you to the new place. The notice that asks for a license points there too.
Decryption key:
WooCommerce RedSys Gateway v32.1.0
2026.09.09 - version 32.1.0
* SECURITY: The plugin was writing the address of every shopper's order-received page into its own log file on every payment, and that address contains the order key - the private token that WooCommerce puts in the shopper's payment link and that this plugin requires before it will show an order. Anyone able to read the log file could therefore open those orders and see the name, email, telephone and addresses on them. It happened whether or not the shop had switched debug logging on, because this one place wrote to the log without checking that setting. It now respects the debug setting like every other log the plugin writes, and the key is replaced with "[redacted]" before anything is written, so it is not recorded even with logging switched on. That replacement was then applied to every log line the plugin writes rather than to the one that was reported: around ninety further lines across the gateways printed the same addresses whenever debug logging was on, including the ones that dump the whole message sent to the bank. Log files already written still contain those addresses: if you have them, delete them.
* FIX: With InSite, paying with a card the shopper had saved could take the money and still show the order as failed. When the bank approves such a payment without asking the shopper to confirm with their bank app - which is what happens with a saved card - the plugin was looking for the result in the wrong place, found nothing, and treated "nothing" as a refusal. The charge had already gone through, so shoppers who were told the payment had failed paid a second time and were charged twice. The result is now read from the bank's own signed answer, the same one the rest of the payment already uses. It affected the classic checkout and the block checkout equally, and it also affected subscription renewals. Reported by two shops within days of each other, one of whom traced it to the exact line - thank you.
* FIX: On the card gateway, a payment made with a saved card was completed on the strength of an authorisation number alone, without checking the bank's actual answer beside it. A refused payment that still carried something in that field would therefore mark the order as paid, and the shop would send the goods without having been paid. Both are now required to agree before an order is completed. If the bank's answer is missing altogether the payment is not completed, because there is nothing left that says it was approved; a shop whose bank genuinely omits that field can restore the previous behaviour on purpose with the redsys_allow_payment_without_ds_response filter, which is documented and which cannot be used to accept a payment the bank actually refused.
* FIX: On stores using certain checkout plugins - Fluid Checkout among them - every payment was refused by Redsys with the error SIS0574. The bank requires a short description of the shopper's browser with each payment (its language, its screen size and similar), which the plugin collects through hidden fields it adds to the checkout. Those fields were being added at the moment the card gateway was built, which on those stores happens after another plugin has already asked WooCommerce for the definitive list of checkout fields - and WooCommerce builds that list once and never again. The fields were therefore never created, never filled in and never sent, and the bank refused the payment. They are now added as soon as the plugin loads, before anything can ask for the list, which affects every gateway that needs them - the card gateway, Bizum and the wallets - not only InSite. In InSite the browser description now also travels with the rest of the payment data instead of depending on the order alone, so it survives a checkout that rebuilds itself. Reported by an integrator who had already proved the diagnosis - thank you.
* SECURITY: The page that forwards a shopper to Redsys (and to Bizum) accepted any order number typed into its address, without checking that the person asking for it was the person who placed that order. Because order numbers run in sequence, someone could step through them and read the data the plugin sends to the bank for other customers' orders: name, email, telephone and the billing and delivery address, together with the amount and the description of what was bought. No card number, no security code and no signature key were ever exposed, and nothing could be paid or modified this way. That page now requires the order key that WooCommerce puts in the shopper's own payment link, so a request that does not belong to the order is refused with a "Forbidden" page instead of being answered. The same check was added to the payment pop-up on the checkout page. Reported by the security team at Tivify (TVUP Streaming Media), who described the problem clearly and gave us the time to fix it before saying anything publicly - thank you.
* FIX: If a payment was cancelled or refused, the shopper came back to the shop but the order was left pending and the basket was not restored. The address the plugin gave the bank to send the shopper back to was written in the form used for links inside a web page, not the form used for a real address, so the shop received the return without the order reference, its number or its security token and had nothing to cancel. It affected Bizum, Google Pay, Apple Pay, direct debit, bank transfer, InSite and the card gateway whenever the "return to" setting is set to cancel the order. On MasterPass the same address was being sent completely empty, because of a typing mistake of a single character repeated on three lines. All of it now goes through a single shared piece of code, so a gateway added in the future cannot get it wrong again.
* FIX: In the pop-up (modal) payment mode, cancelling a payment did nothing and the shopper was left on the cart with the order still pending. The address the plugin sent the browser to was being written into the page in a way the browser reads as a link inside a document rather than as a web address, so everything after the first parameter was discarded - the order reference, its number and its security token all disappeared, and WooCommerce had nothing to cancel. The same flaw affected the address the shopper is returned to after paying, where it silently dropped a tracking parameter. Both are fixed, in the card gateway and in the InSite gateway, and the corrected behaviour was verified in a real browser.
* FIX: The checkout could die with a critical error, instead of sending the shopper to the bank, for a logged-in customer whose customer record had never been changed since it was created. The plugin builds a set of security data for the bank on every payment, and one of the fields is the date the customer account was last modified - which WooCommerce leaves empty for an account that has never been touched, typically one created by an import, a migration, or automatically by another plugin. The plugin read that empty date as if it were a real date and the payment page stopped there. It now falls back to the date the account was created, which is what "never modified" means, and the same protection was added to the equivalent code used by subscriptions - where the same empty date was silently being reported to the bank as "modified today", which is wrong information for the bank's fraud checks.
* SECURITY: The three preauthorization buttons in the order screen (authorise, cancel, charge a deposit) and the PayGold customer search accepted their requests without a security token. The permission check was already in place, so only a shop manager or administrator could ever use them, and nobody else could have run them - but an administrator who was already logged in could have been tricked into firing one from another website without noticing. All four now carry and verify a WordPress security token, which closes that path.
* FIX: Redsys and the other gateways could disappear from the checkout for everyone, including ordinary shoppers, on stores where the "show only to these users" list in test mode had never been filled in. The plugin read that empty setting as "show it to one user whose id is nothing", which matches nobody, so the payment method was hidden from every visitor. It only affected stores whose settings were written by something other than the settings screen - an import, a migration, or the plugin's own management API - because saving that screen by hand stores a different empty value that never triggered it. Fixed in the nine gateways that shared the same code.
* FIX: Subscriptions paid with Apple Pay or Google Pay by a customer without an account never obtained the recurring payment permission from the bank, so the first renewal failed with a note saying there was no card. It happened on stores where the general "allow customers to create an account during checkout" option is switched off, which is common on stores that allow guest checkout: the wallet payment paths never saw WooCommerce Subscriptions' own override of that option, so no account was created and, without an account, the bank permission could not be stored. Fixed in the four places that handle it (Apple Pay and Google Pay, on both the classic and the block checkout).
* FIX: The block checkout's payment script was built against a version of React that WordPress itself does not accept. A development-only dependency pulled a newer React into the build, and WordPress rejects elements produced by it, so the payment method could fail to appear on the block checkout. The build now pins the version WordPress uses and the script has been rebuilt.
* CHANGE: When a subscription renewal fails, the note added to the order now says exactly which step failed and which merchant code and terminal were used for the attempt. Until now all six possible failures wrote the same uninformative note, which made a failed renewal almost impossible to diagnose without access to the store - especially on stores where the debug log is not being written.
* CHANGE: When Apple Pay cannot validate the shop with Apple, the log now records Apple's own explanation and whether the certificate files can be read. Apple answers with a generic "Expectation Failed" and puts the real reason in the body of its reply, which was never being recorded, so those failures used to be a dead end.
* NEW: The WooCommerce status report (WooCommerce - Status) now also lists what is switched on in the Redsys "Advanced settings" tab: push notifications, sequential invoices, QR codes, saved cards, order status overrides, conditional rules, subscriptions, e-mail reconciliation, the agentic commerce protocols and the management app API. Credentials are never printed - each one is reported only as set or not set. It is included when you copy the report to send it for support, which is the point: a support request now arrives with the configuration already in it.
* CHANGE: The distributed plugin no longer contains the project's own development and build scripts, its local test environment configuration, its editor and git-hook directories, its developer README or an internal security review document. None of it was ever loaded when the plugin runs, but none of it belongs on a shop's server either. What the package contains is now checked automatically, before every release, against a list of what the plugin really ships, so something added to the project in the future cannot travel inside the zip unnoticed.
* FIX: The cart and the checkout could become noticeably slow, for logged-out visitors too, on stores with saved cards or subscriptions. The plugin's internal helper WCRed() built a brand new copy of its global object every single time it was called, and that object registers three WordPress hooks the moment it is built. WordPress does not replace those hooks, it adds them, so on a store where the helper is called once per saved card or subscription the same three checks ended up registered hundreds of times and were re-run, all of them, every time WooCommerce assembled the list of available payment gateways. On a store that reported the problem this reached around 438 duplicated registrations per page load and about 1.7 seconds of PHP work on the cart page, of which only 56 milliseconds were database queries. The helper now builds that object once and reuses it, so the hooks are registered exactly once per request. Nothing about the plugin's behaviour changes: the object holds no per-request data. The same one-object-per-request treatment was applied to the WCPSD2() helper, which had the identical shape.
* FIX: On a small share of stores the Agentic Commerce (UCP) message-signing key was written in a form that could never be used, so every signature check against it failed and the published key document did not follow the standard. When the plugin created that key, one of its two coordinates occasionally came back from OpenSSL one byte shorter than the standard requires - about 1 store in 135 - and the plugin stored it as it was instead of padding it. From that moment the store could not verify its own signatures, and no external agent could either, until the key was rotated. The key is now stored padded to the required length, and a key already stored in the short form is repaired automatically the first time it is read, so no merchant has to rotate anything.
* FIX: On shops running PHP 8.0 or older, switching on the e-mail reconciliation broke the page with a server error instead of simply not working. The plugin now checks first and leaves a clear note in its log. The feature itself still needs PHP 8.1.
* SECURITY: The Agentic Commerce Protocol could end up switched on without anyone choosing it, on shops that update automatically. It publishes addresses that machines can talk to, so it is meant to be off unless you turn it on - and now it is. If you did switch it on, nothing changes for you.
* FIX: Background jobs were piling up into dozens of copies of themselves in the WooCommerce scheduled actions list. Fixed everywhere the plugin schedules anything, and the copies already there are cleared automatically.
* CHANGE: The e-mail reconciliation job now exists only while that feature is switched on, and only once. Before, it was created on every shop and woke up every five minutes doing nothing.
* FIX: A notification to the mobile app could be lost without any error if it was sent at the wrong moment.
* FIX: PHP warnings appeared in the server log on every visit to the "pay for order" page, from the Apple Pay and Google Pay gateways. Nothing was broken for shoppers, but the debug log for those gateways was not recording anything from that step - so anyone trying to diagnose a problem there was looking at a fault, not at silence. Reported by a merchant, and found in three gateways rather than the one reported - thank you.
* FIX: Turning the debug log on to look into a card payment problem produced warnings instead of the information you turned it on for.
* FIX: The "Connect with Google" button in the e-mail reconciliation settings was never displayed. Granting access was already possible by filling in the Google details and pressing "Save changes", so this restores a shortcut rather than unlocking the feature.
* SECURITY: The Google library bundled with the plugin has been updated, fixing two flaws in the part that makes network requests.
* CHANGE: All the translations are complete again. Sixty-nine texts added by recent versions were still showing in English - settings labels, the status report, and a few messages a shopper can see. Spanish, Catalan, Basque, Galician, French and Portuguese are back at one hundred per cent.
* NEW: You can now decide whether customers are offered "Add a credit card for Subscriptions" in My account - Payment methods. Until now that option appeared by itself as soon as a subscriptions plugin was active, with no way to remove it, which is not what every shop wants: on a shop where the card for a subscription is always captured during the purchase, it only invited customers to store a card nothing would ever charge. The new switch is in Redsys - Advanced settings - Saved Cards, it starts switched on so nothing changes for shops that were already offering it, and switching it off leaves the 1-click card on its own. It is also reported in the WooCommerce status report.
* FIX: The plugin sent the shop an e-mail saying "Redsys is not sending tokenization fields" after payments in which Redsys had sent every one of them. The check behind that notice tested a variable that does not exist anywhere in the plugin, and a test on something that does not exist is always true, so the warning went out on every payment that saved a card. Merchants were taking it to their bank, which correctly answered that the terminal was fine. The notice now reports only real absences, and it names in the log which field was missing - the expiry date, the card brand or the card number - instead of only saying that something was. It also had to stop reading the brand after the plugin had turned it into a display name, because that conversion answers "Unknown" when there is no brand, which would have turned the warning into one that could never appear at all. The same block was writing "unknown" as the card number in the debug log on every payment, through a variable name that carried one letter too many; it now writes the real masked number.
* FIX: Searching the Redsys tokens screen (WooCommerce - Redsys tokens) by e-mail or username could not find any card saved after the first twenty-five. The screen asked the database for one page of tokens and then searched inside that page, and since it asked for them in no particular order, that page was always the twenty-five oldest tokens in the shop - so the recently saved cards, which are the only ones anybody looks for, were unreachable. The search now runs in the database, over every token, and the listing arrives newest first. The counter above the table and the list below it can no longer disagree, sorting by username or e-mail now sorts the whole table instead of the visible page, and the screen no longer loads every token in the shop into memory just to count them, which on shops with thousands of saved cards it did on every page load.
* CHANGE: The token that guards the "add a card" link is now compared in constant time, like every other secret this plugin compares. Timing that comparison over the internet is not a practical attack, so nothing was exploitable; the inconsistency was the defect, because this was the one comparison left behind when the rest were migrated during the signature work.
Decryption key:
WooCommerce RedSys Gateway v32.0.0
2026.07.28 - version 32.0.0
* NEW: Manage your store from a native app. This release turns on the management app API that until now shipped hidden inside the plugin. Your store can be connected to PackDesk, the native macOS management app, to work with orders, refunds, products and customers without opening the WordPress dashboard. The API is served under the redsys-manager/v1 namespace and is strictly opt-in: it is OFF by default, it requires HTTPS and an active license, and no app can reach the store until a merchant enables it. It provides an order picking queue and order updates, product and customer routes, a "changes" delta feed so the app syncs only what changed, safe write retries through an Idempotency-Key header, and a request rate limit applied per employee (per user, never per IP), so several employees sharing a single connection never interfere with each other.
* NEW: A new "Behaviors towards the APP" section in the Redsys advanced settings (WooCommerce - Settings - Redsys - Advanced Settings) to control how the store behaves towards the app: enable or disable the API, allow or restrict refunds for the Customer service profile (refunds are limited to the Administrator profile by default), require a minimum app version, and set the requests-per-minute limit per employee (default 300, set 0 to disable it).
* NEW: A per-user "App profile" on the WordPress user edit screen, so each employee who connects from the app operates under a profile - for example Administrator or Customer service - that decides what the app lets them see and do, including whether they may issue refunds.
* NEW: A new "Apps and Plugins" section in the Redsys advanced settings: a read-only overview of the native app and the rest of the plugins, websites and skills, all reachable from one place.
* CHANGE: Compatibility declared with WooCommerce 11. The plugin's "WC tested up to" header now reads 11.0, so WooCommerce no longer warns that the gateway has not been tested with the version you are running. The minimum supported WooCommerce is unchanged (7.4).
* NEW: PackDesk is now published on the Mac App Store, and the official "Download on the Mac App Store" button is shown at the top of the "Behaviors towards the APP" section and in the featured-app area of "Apps and Plugins", so the app can be installed straight from the store settings. The button uses Apple's own artwork in the language of the administrator viewing it - English, Spanish, Catalan, French or Portuguese, with English used for Basque and Galician because Apple does not publish a badge for them - and it opens the App Store of each visitor's own country. The app entry now shows the published version instead of the beta, and states that it requires macOS 26 Tahoe or later.
* FIX: The product QR code did not appear on stores whose media library is offloaded to an external service such as Cloudflare Images. The QR image was registered in the media library correctly, but the plugin saved and displayed a URL it had built by hand from the local uploads folder instead of asking WordPress for the attachment's real URL, so on an offloaded store that address pointed at a file that is no longer served locally and the image was broken. The QR URL is now resolved through the media library (wp_get_attachment_url), the attachment id is stored alongside it, and the address is resolved every time the QR is shown, so it follows the file wherever it is served - including offloading that was enabled after the QR was created. Existing QR codes are healed automatically the first time their product is opened; if one cannot be matched, the "Regenerate QR Code" link rebuilds it correctly.
* FIX: A Bizum payment could be charged at the bank yet leave the order pending, with the log showing "Signature verification failed in successful_request". The order-completion step in one of the two Bizum gateways verified the bank notification with the gateway's plain configured signature key, while the operation had been signed with the per-order key actually used for it - as happens on stores with a per-user or dual/test terminal, or the bizum_modify_data_to_send filter. The notification passed the first validation and was then rejected by this second check, so the money was taken but the order stayed pending. The order-completion step now resolves the signing key exactly like the notification validation - and like the other Bizum gateway already did - from the order meta, then the request transient, then the settings key for the order's customer, so both agree.
Decryption key:
WooCommerce RedSys Gateway v31.0.5
*** Redsys Gateway Change Log ***
2026.07.02 - version 31.0.5
* FIX: Subscription renewals could still get stuck in an endless SIS0051 ("número de pedido repetido") loop after 31.0.4. The 31.0.4 fix released the stored order number only when the decline arrived as a signed Ds_Response without an authorisation code, but Redsys reports a duplicate order number as a plain errorCode (SIS0051) in the trataPeticion response, which the plugin handles through the request-error path — so the stored number was never released and every retry resent the exact same DS_MERCHANT_ORDER (already burned at Redsys by attempts made before updating), failing again with SIS0051 forever. Renewal charges now ALWAYS generate a brand-new order number at the start of every attempt and never read a previously stored one: the iniciaPeticion/trataPeticion pair of the attempt shares that freshly generated number (so they cannot mismatch, SIS0502), duplicate concurrent workers are stopped by the renewal lock before the number is generated, and the last number sent is still persisted to order meta so refunds and the payment notification (IPN) resolve the right order. Stores stuck in the SIS0051 loop self-heal on the next scheduled retry after updating, with no manual action needed. Applies to the Redirection and InSite gateways and every subscription plugin routing through them (Google Pay / Apple Pay delegate to Redirection).
2026.07.01 - version 31.0.4
* FIX: Subscription renewals (with any subscription plugin) now respect the configured Redsys order-number type and no longer fail on retry with "número de pedido repetido" (SIS0051). Two problems are fixed. First, the renewal charge generated the Redsys order number ignoring the "Type of order number" setting (redsysordertype/subfix): it always fell back to the default random scheme instead of the type configured for the gateway, unlike the initial checkout payment. It now passes the gateway so renewals honour the same order-number type as checkout. Second, the order number was persisted for the whole order lifetime, so when a renewal charge was declined and the subscription plugin retried it on the same renewal order, the exact same DS_MERCHANT_ORDER was resent and Redsys blocked the legitimate retry as a duplicate. The distinction between a "flow" and a "retry" is now explicit: a single payment flow (its iniciaPeticion/trataPeticion pair, concurrent renewal workers, and any Action-Scheduler re-run of a process that died mid-charge) keeps the same order number to avoid crossing Id Opers (SIS0502) and to stay idempotent against double charges; but once Redsys confirms a decline (a signed response with no authorisation code, i.e. no money moved), the number is released so the next retry generates a fresh, unique one honouring the configured type. The reset fires ONLY on a confirmed decline, never on transport/timeout errors where the outcome is unknown, so a lost-response re-run can never double charge. Applies to the Redirection and InSite gateways and to every subscription plugin that routes through them (WooCommerce Subscriptions, Subscriptions for WooCommerce, YITH, WebToffee, SUMO, Advanced Subscriptions; Google Pay and Apple Pay delegate to the Redirection gateway). As a safety net, whenever no valid order-number type is configured (empty or a legacy/unrecognised value) the generator now ALWAYS falls back to the default "3 random digits + zeros + order id" scheme, the only one that never collides on retries. Note: the "simple order number" type has no random component, so it is incompatible with subscription retries by design and should not be used when subscriptions are active.
Decryption key:
WooCommerce RedSys Gateway v31.0.3
*** Redsys Gateway Change Log ***
2026.06.27 - version 31.0.3
* SECURITY: Removed a notification signature-bypass that could let an anonymous request mark an order as paid when the SHA-256 secret was left empty/misconfigured. The Redsys IPN listener (public wc-api endpoint) had a legacy fallback that, when no secret was configured, accepted a notification solely because the posted Ds_MerchantCode matched the merchant FUC - a public, non-secret value an attacker can supply. That merchant-code-only acceptance has been removed from every gateway (Redirection, Bizum, Bizum InSite, Google Pay checkout and redirection, Apple Pay, PayGold, Direct Debit, MasterPass and Bank Transfer): when there is no secret to verify the HMAC, the request now fails closed (HTTP rejection) instead of being trusted. In addition, the shared verification routine (WooRedsysAPI::verify_signature_notif) now returns false whenever the merchant key or the received signature is empty, so neither check_ipn_request_is_valid() nor successful_request() can complete a payment on an attacker-computable empty-key HMAC. InSite already required a valid signature (no merchant-code fallback) and Inespay is unaffected (it matches orders by its own payin id). Real stores are unaffected because a configured secret is mandatory to take payments in the first place.
* NEW: "Apps and Plugins" section under Redsys Advanced -> Redsys Advanced Settings. A read-only landing page that showcases the native macOS management app (with download, requirements and "coming soon" platforms) and lists the rest of the free and premium plugins, websites and portals, Claude skills and developer profiles by José Conti, each grouped by type with a link. Every list is filterable (redsys_apps_plugins_mac_app, redsys_apps_plugins_free, redsys_apps_plugins_premium, redsys_apps_plugins_webs, redsys_apps_plugins_skills, redsys_apps_plugins_profiles).
* FIX: Bizum notifications were rejected with a signature verification error, leaving the order unpaid even though the payment had been authorized at Redsys. The merchant key and the order number were correct (the request signature matched perfectly), but the notification signature is an HMAC computed over the Ds_MerchantParameters string exactly as received, and Bizum notifications arrive with the trailing base64 "=" padding stripped while Redsys signs over the canonically padded value, so the locally computed HMAC never matched. The shared notification routine (create_merchant_signature_notif in WooRedsysAPI) now re-pads the payload to a multiple of four before hashing, and the verification (verify_signature_notif) now compares both signatures ignoring the trailing "=" padding (which carries no entropy, so the comparison stays constant-time). Card payloads are already canonical and are left untouched, so every other gateway keeps working unchanged. This routine is shared by all notification handlers (Redirection, Bizum, InSite, PayGold, Google Pay, Apple Pay, Direct Debit, Bank Transfer and the REST/A2A clients).
* FIX: Card and wallet notifications could be rejected with a "signature mismatch", so the customer returning to the thank-you page (and the server-to-server IPN) failed to mark the order as paid until a later IPN retry happened to succeed; refunds and PayGold links paid later could stay unconfirmed. Two padding issues are involved: besides the Bizum payload padding above, Redsys delivers the notification signature (Ds_Signature) in URL-safe base64 with the trailing "=" stripped, while the locally computed signature keeps it - so a strict comparison fails for ordinary card payments too. The padding-tolerant comparison lives in verify_signature_notif(), but most handlers were still comparing the signature inline with a strict hash_equals()/!== that re-introduced the sensitivity. Every handler now delegates to verify_signature_notif(), so the fix reaches all of them: card Redirection (both IPN validators and the capture/refund REST-SOAP response checks), Bizum, Bizum InSite, InSite (IPN, successful_request and the two REST-response validators), PayGold, Google Pay (checkout and redirection), Apple Pay, Direct Debit, Bank Transfer, MasterPass and the InSite REST client. Regression introduced when the per-gateway signature checks were unified onto verify_signature_notif() with a strict, padding-sensitive comparison.
* FIX: Bizum notifications on multi-currency / dual-terminal stores (those routing each order to a different terminal through the bizum_modify_data_to_send filter or a conditional rule) now resolve the real per-order signing key before verifying the signature (the customer-adjusted settings key, the transient saved when the payment form was generated, or the _redsys_secretsha256 order meta), and an unverifiable notification is rejected with HTTP 400.
* FIX: InSite card payments that required a 3DS challenge showed a blank verification screen in Safari (iPhone/Mac), so the customer could not enter the SMS code/PIN and the payment failed (the same flow worked in Chrome). The challenge itself was already a full-page, top-level navigation, but before it the plugin redirected the browser to the issuer's 3DS Method URL (threeDSMethodURL) to fingerprint the browser, and Safari's Intelligent Tracking Prevention blocks the third-party cookies that step needs, leaving a blank ACS page (symptom: the ACS URL arrives with ";jsessionidpa=" because the cookies are not flowing). The 3DS Method browser step is optional, so the plugin no longer redirects the browser to threeDSMethodURL: it always sends threeDSCompInd = 'N' and continues straight to authentication. Applied to every InSite flow - new card and saved card (one-click/token), on both block and classic (shortcode) checkouts - and to the Redirection gateway's REST/token flows (pay_with_token_c, receipt_page and successful_request), since the same blank screen could appear when charging a saved-card token.
* FIX: When an InSite card payment failed because a required checkout field was missing or its data did not match (for example an empty surname produced a "signature mismatch"), the error message blamed the card ("...enter your card details again"), so customers thought their card had been rejected and abandoned the order. The message is now neutral and points to the checkout fields first: it asks the customer to check that all the checkout fields (name, surname, address, etc.) and the card details are filled in correctly before trying again. Applied to both the classic and block (Blocks) checkouts.
* FIX: Refunds and delayed payments of orders with large order IDs (the "1 billion bug" already fixed for instant checkout) were recorded against the wrong order, or not recorded at all. The Redsys notification (IPN) recovers the WooCommerce order ID from the order number through clean_order_number(), which first looks up a transient saved when the order number was generated and otherwise fell back to a substr/ltrim heuristic that drops the high-order digits of IDs with 10 or more digits. That transient has a 1h TTL, so the fallback was hit whenever the notification arrives more than an hour after the order number was generated: every refund (processed days or weeks later) and PayGold payment links (paid by the customer later), among others. Three changes make this robust for every payment method: (1) the shared refund routine (ask_for_refund) now re-saves the order-number to real-order-ID mapping at refund time with a 24h TTL; (2) clean_order_number() now, when the transient is gone, reverse-looks up the order by the persisted order-number meta (_payment_order_number_redsys / _redsys_transaction_id2) before ever using the lossy heuristic; and (3) PayGold now persists the order number to meta when the link is created, so a link paid much later still resolves to the exact order. Applies to every gateway (Redirection, InSite, Bizum, Bizum InSite, Google Pay, Apple Pay, PayGold and Direct Debit). Inespay is unaffected (it matches orders by its own payin id).
* DEV: Removed the noisy debug console.log output from the production (minified) frontend scripts (Apple Pay, Google Pay, capture-order-id and the express-checkout modals). The Apple Pay express script in particular logged on every DOM change (it watches the whole document for its button), which flooded the browser console on the Blocks checkout. The minified files now strip console.log/console.warn/console.info/console.debug while keeping console.error; the un-minified sources are unchanged for development.
* FIX: InSite card payments on the block-based (Blocks) checkout failed the FIRST time with "msg18" (the customer saw "check that the checkout/card fields are filled in") and only worked on the second attempt. The Redsys InSite SDK requires the page to send a "domain" message to the card iframe so Redsys can validate the merchant; the SDK does this through an inline onload="setMerchantDomain(0)" on the iframe. The block script overwrote that handler with its own iframe.onload (used to size the iframe) right after the first render, so the merchant domain was never sent and Redsys rejected the tokenisation with msg18 ("incorrect validation by the commerce"). On the automatic form refresh the overwrite did not run, so the second attempt worked. The plugin now calls setMerchantDomain explicitly after building the form (as the SDK's own pay-button integration does) and no longer overwrites the iframe onload, so the first attempt works.
* FIX/DEV: InSite Blocks checkout - made the Redsys postMessage handling more robust and added end-to-end diagnostics. The handler now accepts messages from any Redsys subdomain (sis.redsys.es, sis-t.redsys.es, sis-d.redsys.es) instead of requiring an exact host/port match (Redsys posts from more than one host), removes any listener left by a previous render so a single token cannot trigger multiple submissions, and clears the token/error fields after reading them so a stale re-fire cannot resend. When InSite debug logging is enabled, the whole client-side tokenisation step (order number, Redsys postMessage, token/error code, save and place-order) is mirrored into the "insite" WooCommerce log, so first-attempt failures that never reach PHP can be diagnosed.
* FIX: InSite card payments on the block-based (Blocks) checkout were rejected by Redsys with SIS0574 ("EMV3DS authentication operation rejected, browserUserAgent not indicated"): the 3DS browser fingerprint (user agent, screen size, language, colour depth, timezone) never reached the order, because the hook that normally copies it onto the order (woocommerce_checkout_create_order) does not run on the Store API (Blocks) checkout. The InSite Blocks form now collects the fingerprint and sends it together with the operation token, and it is written onto the real order (next to the token) before process_payment runs, so the EMV3DS authentication has the data it needs.
* FIX: InSite card payments on the block-based (Blocks) checkout were rejected with an "error code without token" (shown to the customer as "check that the checkout/card fields are filled in"), so the card could not even be tokenised after a few attempts. Because the order does not exist yet on the Blocks checkout (order id 0), the prepared Redsys order number was generated from id 0, which produced an almost constant value - only ~999 possible numbers, all ending in nine zeros - and Redsys rejects a reused order number ("pedido repetido", SIS0051). When the draft order id is not yet available, the InSite Blocks form now uses the same temporary order number as the InSite shortcode checkout (create_checkout_insite_number: always starts with 1, globally unique through a shared incremental counter), so it never collides; when the draft order id is available, the Redsys number is built from it. The number is re-linked to the real order id when the order is placed.
* FIX: InSite card payments on the block-based (Blocks) checkout failed: the customer saw a misleading "check that the checkout/card fields are filled in" error and the order was never paid (the browser console showed a 404 on the save_order_data request). The cause is that current WooCommerce no longer creates the order until the customer presses "Place order" - during card entry the Blocks checkout store returns order id 0 - so the InSite operation token (idOper) and the prepared Redsys order number could not be persisted: the previous flow posted them to a REST route (save_order_data) that tried to attach them to order 0 and returned "Invalid order" (404), and the generated order number was mapped to order 0 (so even a later notification could not find the order). Now, when the card is tokenised, the token and the prepared order number are stored in the WooCommerce session via admin-ajax (the WC session is not available on custom REST routes, which is why the prior REST approach could not use it), and they are moved onto the real order while WooCommerce is creating it from the checkout request (woocommerce_store_api_checkout_update_order_from_request), before process_payment runs, so process_payment_block() finds _insite_token and _payment_order_number_redsys as it does on the classic checkout. The order-number transient is also re-mapped to the real order id so the notification (IPN) resolves the order. The browser-fingerprint (3DS) data already used this same session route. The classic/shortcode checkout is unaffected.
Decryption key:
WooCommerce RedSys Gateway v31.0.2
Version 31.0.2Released on 2026.06.16
- The redsys_modify_data_to_send filter now receives 'context' => 'add_payment_method' and 'user_id' in the data array for the "Add payment method" flow, so custom snippets and conditional rules can route the tokenization to the right terminal (terminal + SHA256) without relying on an order that does not exist in this flow.
- Adding a card from My Account ("Add payment method") on multicurrency stores could be rejected by Redsys with a currency error. The request was sent with the customer's session currency (e.g. ARS, 32) but the default terminal, which is configured for another currency (e.g. EUR, 978). Card tokenization is a zero-amount operation with no order behind it, so if no filter or conditional rule routes the request to another terminal, the store base currency is now sent, always matching the default terminal configuration.
- Adding a card from My Account (or via the profile email link) always registered the card at Redsys as one-click (DS_MERCHANT_COF_TYPE 'C'), even when the customer selected the subscriptions option. The token type was read from the wrong internal key, so 'R' was never sent. The token was stored correctly as R in WooCommerce, but the COF agreement was created as C at Redsys, which could cause some issuers to decline later subscription renewals (MIT) made with those tokens. Cards added with the subscriptions option now correctly send DS_MERCHANT_COF_TYPE 'R'. Tokens created while the bug was present cannot be reclassified; if a renewal is declined, ask the customer to re-add the card.
- Payments made with a saved card (token R) and subscription renewals did not honor the preauthorization settings. With "Preauthorize all orders" enabled (or a product marked for preauthorization), the charge was executed as a regular sale (type 0) but the order was still marked as "Preauthorized", so confirming the preauthorization later failed at Redsys with SIS0059 ("No operation exists on which to perform the confirmation"). Both flows now send a real type 1 preauthorization that can be confirmed later, and an order is only marked as "Preauthorized" when a real preauthorization was executed. This also enables preauthorized subscription renewals (for example goods sold by weight, where each renewal is adjusted before the final charge).
- Updated all translations.
- The merchant SHA-256 secret key is no longer written in plain text to the WooCommerce debug logs. All debug entries now mask the key, showing only its last 4 characters, via the new WCRed()->mask_secret() helper. Applied across all gateways (Redirection, InSite, Bizum, Google Pay, Apple Pay, PayGold, Direct Debit and the Blocks support classes).
- Redsys notification (IPN) signatures are now verified with hash_equals() (constant-time comparison) in all notification handlers, unifying them with the verification already used by InSite and the REST client. Hardening against timing attacks.
- The single-token delete AJAX handler in the tokens management screen now requires the manage_woocommerce capability in addition to the nonce, matching the bulk-delete handler.
WooCommerce RedSys Gateway v31.0.1
Versione 31.0.1Released on 2026.06.09
- Bizum on the payment page (Bizum InSite) did not send the description to Redsys. The actual charge from the modal is made through the REST API (trataPeticionREST), and that request did not include the DS_MERCHANT_PRODUCTDESCRIPTION parameter, so the configured "Redsys Description" (for example "Order ID") reached the Redsys panel empty. The description is now computed from the selected setting and sent in the REST request.
- The countdown in the Bizum payment-page modal showed 7 minutes. It now correctly shows 5 minutes, and the server-side time control that redirects to the checkout has been adjusted accordingly (60 iterations * 5 seconds = 5 minutes).
WooCommerce RedSys Gateway v30.4.1
Version 30.4.1Released on 2026.05.05
=
- "Redsys email to customer" toggle in Redsys Advanced Settings → General to control whether DS_MERCHANT_EMAIL_TITULAR is sent to Redsys. When enabled and the Redsys terminal is configured to notify customers, Redsys sends its own purchase confirmation email to the buyer. Disabled by default — WooCommerce already sends its own order email, so existing installations stop forwarding the customer email to Redsys after the update. Applied to both Redsys Redirection and InSite gateways (classic and Blocks checkouts).
- Apple Pay Express button on the product page failed to open the payment sheet on iOS Safari mobile when the Express custom fields feature was enabled. The pre-payment AJAX call (modal lookup or modal save) ran between the click handler and ApplePaySession.begin(), invalidating the iOS user-activation gesture so Safari silently aborted the session. The button still worked on desktop because desktop Safari is more permissive about gesture propagation.
- Inline Express custom fields on the product page. When the feature is enabled and there are fields to collect, the form is now rendered above the Apple Pay / Google Pay buttons instead of in a post-click modal, with debounced auto-save to session. The click handler validates locally and starts ApplePaySession.begin() synchronously, preserving the iOS user gesture.
- Express custom fields modal AJAX no longer fires when there are no fields to collect on the current page. The product page now precomputes whether any classic or Blocks-registered additional fields exist and disables the modal lookup entirely when the field set is empty, avoiding the gesture-breaking AJAX even on pages where the feature is enabled but no fields apply.
- Inline Express custom fields on the product page now try both Blocks and Classic contexts when reading additional fields, so fields registered through the Blocks API are also rendered on classic product pages.
- Inespay periodic mandate now sends the recurring amount of the subscription instead of the parent order total. The gateway reads the recurring price from WooCommerce Subscriptions, SUMO Subscriptions, YITH WooCommerce Subscriptions, Subscriptions for WooCommerce (WP Swings) and Advanced Subscriptions for WooCommerce, and falls back to the order total only when no subscription amount can be detected. The order note created on mandate creation now includes the recurring amount that was actually sent to Inespay.
- Advanced Subscriptions for WooCommerce (ASWC) support in Inespay — the gateway detects the subscription id from order meta (aswc_subscription) and reads frequency, next payment date, end date and recurring amount via aswc_get_meta_data() to build the periodic mandate.
- Inespay return handler now keeps the intermediate "Creating the mandate…" screen visible for a few seconds even when the periodic mandate link is already known on first load, so customers can read what is happening before being redirected back to Inespay to authorize the recurring mandate.
- Limited Inespay and Google Pay Redirection gateway icons to the same maximum size as Google Pay (max-width 110px, max-height 40px) in the classic checkout, preventing oversized logos when the bank-supplied image is too large.
- PHP warnings "Undefined variable $ship_address_usage / $ship_address_usage_ind" in class-wc-gateway-redsys-psd2.php when a guest customer (not logged in and no user id) checked out with a shipping address. Both variables were only initialized inside the logged-in branch but read in the outer block; they now default to first-use today, matching the existing else-branch behavior.
For activation, use this activator. Exclusively for Babiato.tech members.
https://babiato.tech/free-resources/woo-plugins-activator-activate-all-woo-products.42357/
Decryption key:
WooCommerce RedSys Gateway v30.4.0
=
- Subscriptions section in Redsys Advanced settings to configure credentials and behavior for subscription renewal payments.
- [High]: Added missing cryptographic signature verification in successful_request() for 9 payment gateways: Apple Pay, Bizum Checkout, Bizum Redirect, Google Pay Checkout, Google Pay Redirect, Direct Debit, MasterPass, PayGold, and Bank Transfer. Without this check, payment notifications could be forged to complete orders without actual payment.
- SUMO Subscriptions renewal orders failed because sumo_save_subscription_payment_info() was called with 'payment_method' => 'insite' instead of 'redsys' in the redirect gateway callback. This caused SUMO to set the wrong payment method on renewal orders, triggering the wrong gateway filter and using incorrect credentials.
- YITH WooCommerce Subscriptions were being cancelled prematurely on failed renewals for the Redsys Redirect, InSite, Apple Pay Checkout and Google Pay Checkout gateways. The "no token / expired card" path in doing_scheduled_subscription_payment() (class-wc-gateway-redsys.php and class-wc-gateway-insite-redsys.php) called ywsbs_register_failed_payment() and then returned false, causing the YITH wrapper renew_yith_subscription() to call it again. The double increment of failed_attempts cancelled subscriptions after 1–2 real failures instead of the configured 3 retries. Apple Pay and Google Pay Checkout are also fixed since they delegate to the main Redsys handler.
- version 30.3.1
- [Medium]: Fixed an authenticated account takeover vulnerability that could allow an attacker to assume any user account, including administrators.
- [Low]: Fixed unauthenticated access to order status and user data.
- PayGold link generated from admin order metabox was never saved correctly due to an impossible response code condition in send_paygold_link(). The function now uses the same validation logic as the checkout flow (response code 9998).
- Fixed undefined $description variable in paygold_metabox_save() when sending a PayGold link from the order edit screen.
- Custom notification domain (redsys_url_notify) was broken by check_url() prepending home_url() to URLs that already had a different domain. check_url() now detects absolute URLs and preserves them as-is.
- get_notify_home_url() now automatically adds https:// when the custom notification domain is saved without a scheme.
- PHP 8.3+ compatibility — Fixed deprecated warnings for passing null/false to string functions (trim, strlen) from get_option() calls in get_txnid(), get_token_type(), and connect_standard_imap().
- PHP 8.3+ compatibility — Fixed add_submenu_page(null,...) in setup guide causing strpos()/str_replace() deprecation warnings
For activation, use this activator. Exclusively for Babiato.tech members.
https://babiato.tech/free-resources/woo-plugins-activator-activate-all-woo-products.42357/
WooCommerce RedSys Gateway v30.3.1
Version 30.3.1Released on 2026.03.20
- [Medium]: Fixed an authenticated account takeover vulnerability that could allow an attacker to assume any user account, including administrators.
- [Low]: Fixed unauthenticated access to order status and user data.
- PayGold link generated from admin order metabox was never saved correctly due to an impossible response code condition in send_paygold_link(). The function now uses the same validation logic as the checkout flow (response code 9998).
- Fixed undefined $description variable in paygold_metabox_save() when sending a PayGold link from the order edit screen.
- Custom notification domain (redsys_url_notify) was broken by check_url() prepending home_url() to URLs that already had a different domain. check_url() now detects absolute URLs and preserves them as-is.
- get_notify_home_url() now automatically adds https:// when the custom notification domain is saved without a scheme.
- PHP 8.3+ compatibility — Fixed deprecated warnings for passing null/false to string functions (trim, strlen) from get_option() calls in get_txnid(), get_token_type(), and connect_standard_imap().
- PHP 8.3+ compatibility — Fixed add_submenu_page(null,...) in setup guide causing strpos()/str_replace() deprecation warnings.
=
For activation, use this activator. Exclusively for Babiato.tech members.
https://babiato.tech/free-resources/woo-plugins-activator-activate-all-woo-products.42357/