diff --git a/civicrm.php b/civicrm.php
index cd768d1bde1e2a5ed93c61f5fa84fbcac84890a4..493058e4276b6a72cddab1eeffa83773af4ccab1 100644
--- a/civicrm.php
+++ b/civicrm.php
@@ -2,7 +2,7 @@
 /**
  * Plugin Name: CiviCRM
  * Description: CiviCRM - Growing and Sustaining Relationships
- * Version: 5.69.2
+ * Version: 5.69.3
  * Requires at least: 4.9
  * Requires PHP:      7.3
  * Author: CiviCRM LLC
@@ -36,7 +36,7 @@ if (!defined('ABSPATH')) {
 }
 
 // Set version here: changing it forces Javascript and CSS to reload.
-define('CIVICRM_PLUGIN_VERSION', '5.69.2');
+define('CIVICRM_PLUGIN_VERSION', '5.69.3');
 
 // Store reference to this file.
 if (!defined('CIVICRM_PLUGIN_FILE')) {
diff --git a/civicrm/CRM/Admin/Form/Setting/Mail.php b/civicrm/CRM/Admin/Form/Setting/Mail.php
index 4b49514c34a43201376142b8a0db94361dc67f8a..358c87f81fcf9acf70dcb7bcb9006154e3c44648 100644
--- a/civicrm/CRM/Admin/Form/Setting/Mail.php
+++ b/civicrm/CRM/Admin/Form/Setting/Mail.php
@@ -29,6 +29,7 @@ class CRM_Admin_Form_Setting_Mail extends CRM_Admin_Form_Setting {
     // dev/core#1768 Make this interval configurable.
     'civimail_sync_interval' => CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
     'replyTo' => CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
+    'civimail_unsubscribe_methods' => CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
   ];
 
   /**
diff --git a/civicrm/CRM/Contact/Form/Contact.php b/civicrm/CRM/Contact/Form/Contact.php
index 99d0761d00863b94692ef7e3ee38683708dc810c..d66616d09a4f986fea199e0bd879dfe8fc154d5c 100644
--- a/civicrm/CRM/Contact/Form/Contact.php
+++ b/civicrm/CRM/Contact/Form/Contact.php
@@ -365,7 +365,7 @@ class CRM_Contact_Form_Contact extends CRM_Core_Form {
         // the buildForm adds the contact_sub_type to the form we need to look in _submitValues for it - submitValues
         // is a un-sanitised version of what is in the form submission (_POST) whereas `getSubmittedValues()` retrieves
         // 'allowed' POSTED values - ie values which match available fields, with some localization handling.
-        CRM_Custom_Form_CustomData::preProcess($this, NULL, $this->isSubmitted() ? ($this->_submitValues['contact_sub_type'] ?? []) : $this->getContactValue('contact_sub_type'),
+        CRM_Custom_Form_CustomData::preProcess($this, NULL, $this->isSubmitted() ? ($this->_submitValues['contact_sub_type'] ?? []) : $this->getContactValue('contact_sub_type') ?? $this->_contactSubType,
           1, $this->_contactType, $this->getContactID()
         );
         $this->assign('customValueCount', $this->_customValueCount);
diff --git a/civicrm/CRM/Contribute/Form/Contribution/Main.php b/civicrm/CRM/Contribute/Form/Contribution/Main.php
index 8b5544e590f0b295bec7c9d31ea97d663159ca37..a39d1b06656e5b7229d272cd3cb86b4fc93d7cb7 100644
--- a/civicrm/CRM/Contribute/Form/Contribution/Main.php
+++ b/civicrm/CRM/Contribute/Form/Contribution/Main.php
@@ -1852,9 +1852,9 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
       return 0;
     }
     if (!$this->isQuickConfig()) {
-      return CRM_Member_BAO_MembershipType::getMembershipType($membershipTypeID)['auto_renew'];
+      return CRM_Member_BAO_MembershipType::getMembershipType($membershipTypeID)['auto_renew'] ?? 0;
     }
-    $membershipTypeAutoRenewOption = CRM_Member_BAO_MembershipType::getMembershipType($membershipTypeID)['auto_renew'];
+    $membershipTypeAutoRenewOption = CRM_Member_BAO_MembershipType::getMembershipType($membershipTypeID)['auto_renew'] ?? 0;
     if ($membershipTypeAutoRenewOption === 2 || $membershipTypeAutoRenewOption === 0) {
       // It is not possible to override never or always at the membership block leve.
       return $membershipTypeAutoRenewOption;
diff --git a/civicrm/CRM/Mailing/BAO/Mailing.php b/civicrm/CRM/Mailing/BAO/Mailing.php
index c476818874fd6bf8e24fae4db62a58c9628057d4..ad551aeb112d546e0d2acb87b5540ff948a30d99 100644
--- a/civicrm/CRM/Mailing/BAO/Mailing.php
+++ b/civicrm/CRM/Mailing/BAO/Mailing.php
@@ -2439,19 +2439,19 @@ LEFT JOIN civicrm_mailing_group g ON g.mailing_id   = m.id
   public static function self_hook_civicrm_pre(\Civi\Core\Event\PreEvent $event) {
     if ($event->action === 'create') {
       $params = &$event->params;
-      $params['created_id'] ??= CRM_Core_Session::singleton()->getLoggedInContactID();
-      $params['override_verp'] ??= !Civi::settings()->get('track_civimail_replies');
-      $params['visibility'] ??= 'Public Pages';
-      $params['dedupe_email'] ??= Civi::settings()->get('dedupe_email_default');
-      $params['open_tracking'] ??= Civi::settings()->get('open_tracking_default');
-      $params['url_tracking'] ??= Civi::settings()->get('url_tracking_default');
-      $params['header_id'] ??= CRM_Mailing_PseudoConstant::defaultComponent('Header', '');
-      $params['footer_id'] ??= CRM_Mailing_PseudoConstant::defaultComponent('Footer', '');
-      $params['optout_id'] ??= CRM_Mailing_PseudoConstant::defaultComponent('OptOut', '');
-      $params['reply_id'] ??= CRM_Mailing_PseudoConstant::defaultComponent('Reply', '');
-      $params['resubscribe_id'] ??= CRM_Mailing_PseudoConstant::defaultComponent('Resubscribe', '');
-      $params['unsubscribe_id'] ??= CRM_Mailing_PseudoConstant::defaultComponent('Unsubscribe', '');
-      $params['mailing_type'] ??= 'standalone';
+      $params['created_id'] = $params['created_id'] ?? CRM_Core_Session::singleton()->getLoggedInContactID();
+      $params['override_verp'] = $params['override_verp'] ?? !Civi::settings()->get('track_civimail_replies');
+      $params['visibility'] = $params['visibility'] ?? 'Public Pages';
+      $params['dedupe_email'] = $params['dedupe_email'] ?? Civi::settings()->get('dedupe_email_default');
+      $params['open_tracking'] = $params['open_tracking'] ?? Civi::settings()->get('open_tracking_default');
+      $params['url_tracking'] = $params['url_tracking'] ?? Civi::settings()->get('url_tracking_default');
+      $params['header_id'] = $params['header_id'] ?? CRM_Mailing_PseudoConstant::defaultComponent('Header', '');
+      $params['footer_id'] = $params['footer_id'] ?? CRM_Mailing_PseudoConstant::defaultComponent('Footer', '');
+      $params['optout_id'] = $params['optout_id'] ?? CRM_Mailing_PseudoConstant::defaultComponent('OptOut', '');
+      $params['reply_id'] = $params['reply_id'] ?? CRM_Mailing_PseudoConstant::defaultComponent('Reply', '');
+      $params['resubscribe_id'] = $params['resubscribe_id'] ?? CRM_Mailing_PseudoConstant::defaultComponent('Resubscribe', '');
+      $params['unsubscribe_id'] = $params['unsubscribe_id'] ?? CRM_Mailing_PseudoConstant::defaultComponent('Unsubscribe', '');
+      $params['mailing_type'] = $params['mailing_type'] ?? 'standalone';
     }
     if ($event->action === 'delete' && $event->id) {
       // Delete all file attachments
diff --git a/civicrm/CRM/Mailing/Form/Unsubscribe.php b/civicrm/CRM/Mailing/Form/Unsubscribe.php
index f0a8e0d1f9d453cbd68d67b85ab90de0a1aeed48..6abca91f813df92ce399ea0c7a50d6edd725d1fc 100644
--- a/civicrm/CRM/Mailing/Form/Unsubscribe.php
+++ b/civicrm/CRM/Mailing/Form/Unsubscribe.php
@@ -64,7 +64,7 @@ class CRM_Mailing_Form_Unsubscribe extends CRM_Core_Form {
       );
     }
 
-    list($displayName, $email) = CRM_Mailing_Event_BAO_MailingEventQueue::getContactInfo($queue_id);
+    [$displayName, $email] = CRM_Mailing_Event_BAO_MailingEventQueue::getContactInfo($queue_id);
     $this->assign('display_name', $displayName);
     $nameMasked = '';
     $names = explode(' ', $displayName);
diff --git a/civicrm/CRM/Mailing/Page/Unsubscribe.php b/civicrm/CRM/Mailing/Page/Unsubscribe.php
index 349ee59d2a7afa9513ce00b7a1312cd35c19e06d..218fe4c82873994164173f7d9ce67a5799b5e1d4 100644
--- a/civicrm/CRM/Mailing/Page/Unsubscribe.php
+++ b/civicrm/CRM/Mailing/Page/Unsubscribe.php
@@ -14,7 +14,7 @@
  * @package CRM
  * @copyright CiviCRM LLC https://civicrm.org/licensing
  */
-class CRM_Mailing_Page_Unsubscribe extends CRM_Mailing_Page_Common {
+class CRM_Mailing_Page_Unsubscribe extends CRM_Core_Page {
 
   /**
    * Run page.
@@ -25,8 +25,44 @@ class CRM_Mailing_Page_Unsubscribe extends CRM_Mailing_Page_Common {
    * @throws Exception
    */
   public function run() {
-    $this->_type = 'unsubscribe';
-    return parent::run();
+    $isOneClick = ($_SERVER['REQUEST_METHOD'] === 'POST' && CRM_Utils_Request::retrieve('List-Unsubscribe', 'String') === 'One-Click');
+    if ($isOneClick) {
+      $this->handleOneClick();
+      return NULL;
+    }
+
+    $wrapper = new CRM_Utils_Wrapper();
+    return $wrapper->run('CRM_Mailing_Form_Unsubscribe', $this->_title);
+  }
+
+  /**
+   *
+   * Pre-condition: Validated the _job_id, _queue_id, _hash.
+   * Post-condition: Unsubscribed
+   *
+   * @link https://datatracker.ietf.org/doc/html/rfc8058
+   * @return void
+   */
+  public function handleOneClick(): void {
+    $jobId = CRM_Utils_Request::retrieve('jid', 'Integer');
+    $queueId = CRM_Utils_Request::retrieve('qid', 'Integer');
+    $hash = CRM_Utils_Request::retrieve('h', 'String');
+
+    $q = CRM_Mailing_Event_BAO_MailingEventQueue::verify(NULL, $queueId, $hash);
+    if (!$q) {
+      CRM_Utils_System::sendResponse(
+        new \GuzzleHttp\Psr7\Response(400, [], ts("Invalid request: bad parameters"))
+      );
+    }
+
+    $groups = CRM_Mailing_Event_BAO_MailingEventUnsubscribe::unsub_from_mailing($jobId, $queueId, $hash);
+    if (!empty($groups)) {
+      CRM_Mailing_Event_BAO_MailingEventUnsubscribe::send_unsub_response($queueId, $groups, FALSE, $jobId);
+    }
+
+    CRM_Utils_System::sendResponse(
+      new \GuzzleHttp\Psr7\Response(200, [], 'OK')
+    );
   }
 
 }
diff --git a/civicrm/CRM/Mailing/Service/ListUnsubscribe.php b/civicrm/CRM/Mailing/Service/ListUnsubscribe.php
new file mode 100644
index 0000000000000000000000000000000000000000..f7f891056312fbb25c18a850fe99102138db11bb
--- /dev/null
+++ b/civicrm/CRM/Mailing/Service/ListUnsubscribe.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * Apply a full range of `List-Unsubscribe` header options.
+ *
+ * @service civi.mailing.listUnsubscribe
+ * @link https://datatracker.ietf.org/doc/html/rfc8058
+ */
+class CRM_Mailing_Service_ListUnsubscribe extends \Civi\Core\Service\AutoService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface {
+
+  /**
+   * @var string|null
+   */
+  private $urlFlags = NULL;
+
+  public static function getMethods(): array {
+    return [
+      'mailto' => ts('Mailto'),
+      'http' => ts('HTTP(S) Web-Form'),
+      'oneclick' => ts('HTTP(S) One-Click'),
+    ];
+  }
+
+  public static function getSubscribedEvents() {
+    return [
+      '&hook_civicrm_alterMailParams' => ['alterMailParams', 1000],
+    ];
+  }
+
+  /**
+   * @see \CRM_Utils_Hook::alterMailParams()
+   */
+  public function alterMailParams(&$params, $context = NULL): void {
+    // FIXME: Flexmailer (BasicHeaders) and BAO (getVerpAndUrlsAndHeaders) separately define
+    // `List-Unsubscribe: <mailto:....>`. And they have separate invocations of alterMailParams.
+    //
+    // This code is a little ugly because it anticipates serving both code-paths.
+    // But the BAO path should be properly killed. Doing so will allow you cleanup this code more.
+
+    if (!in_array($context, ['civimail', 'flexmailer'])) {
+      return;
+    }
+
+    $methods = Civi::settings()->get('civimail_unsubscribe_methods');
+    if ($methods === ['mailto']) {
+      return;
+    }
+
+    $sep = preg_quote(Civi::settings()->get('verpSeparator'), ';');
+    $regex = ";^<mailto:[^>]*u{$sep}(\d+){$sep}(\d+){$sep}(\w*)@(.+)>$;";
+    if (!preg_match($regex, $params['List-Unsubscribe'], $m)) {
+      \Civi::log()->warning('Failed to set final value of List-Unsubscribe');
+      return;
+    }
+
+    if ($this->urlFlags === NULL) {
+      $this->urlFlags = 'a';
+      if (in_array('oneclick', $methods) && empty(parse_url(CIVICRM_UF_BASEURL, PHP_URL_PORT))) {
+        // Yahoo etal require HTTPS for one-click URLs. Cron-runs can be a bit inconsistent wrt HTTP(S),
+        // so we force-SSL for most production-style sites.
+        $this->urlFlags .= 's';
+      }
+    }
+
+    $listUnsubscribe = [];
+    if (in_array('mailto', $methods)) {
+      $listUnsubscribe[] = $params['List-Unsubscribe'];
+    }
+    if (array_intersect(['http', 'oneclick'], $methods)) {
+      $listUnsubscribe[] = '<' . Civi::url('frontend://civicrm/mailing/unsubscribe', $this->urlFlags)->addQuery([
+        'reset' => 1,
+        'jid' => $m[1],
+        'qid' => $m[2],
+        'h' => $m[3],
+      ]) . '>';
+    }
+
+    if (in_array('oneclick', $methods)) {
+      $params['headers']['List-Unsubscribe-Post'] = 'List-Unsubscribe=One-Click';
+    }
+    $params['headers']['List-Unsubscribe'] = implode(', ', $listUnsubscribe);
+    unset($params['List-Unsubscribe']);
+  }
+
+}
diff --git a/civicrm/CRM/Mailing/xml/Menu/Mailing.xml b/civicrm/CRM/Mailing/xml/Menu/Mailing.xml
index f3267235d3b0e63651ed96864091c427d07cb84f..7942323fad17df99e2e3f0314443020042dbd53e 100644
--- a/civicrm/CRM/Mailing/xml/Menu/Mailing.xml
+++ b/civicrm/CRM/Mailing/xml/Menu/Mailing.xml
@@ -115,7 +115,7 @@
   <item>
     <path>civicrm/mailing/unsubscribe</path>
     <title>Unsubscribe</title>
-    <page_callback>CRM_Mailing_Form_Unsubscribe</page_callback>
+    <page_callback>CRM_Mailing_Page_Unsubscribe</page_callback>
     <access_arguments>access CiviMail subscribe/unsubscribe pages</access_arguments>
     <is_public>true</is_public>
     <weight>640</weight>
diff --git a/civicrm/CRM/Utils/Check/Component/Mailing.php b/civicrm/CRM/Utils/Check/Component/Mailing.php
new file mode 100644
index 0000000000000000000000000000000000000000..b7288fb8f095be7628b0546ccf198abb5ed59e62
--- /dev/null
+++ b/civicrm/CRM/Utils/Check/Component/Mailing.php
@@ -0,0 +1,46 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+class CRM_Utils_Check_Component_Mailing extends CRM_Utils_Check_Component {
+
+  /**
+   * @return CRM_Utils_Check_Message[]
+   */
+  public function checkUnsubscribeMethods() {
+    if (!\CRM_Core_Component::isEnabled('CiviMail')) {
+      return [];
+    }
+
+    $methods = Civi::settings()->get('civimail_unsubscribe_methods');
+    if (in_array('oneclick', $methods)) {
+      return [];
+    }
+
+    // OK, all guards passed. Show message.
+    $message = new CRM_Utils_Check_Message(
+      __FUNCTION__,
+      '<p>' . ts('Beginning in 2024, some web-mail services (Google and Yahoo) will require that large mailing-lists support another unsubscribe method: "HTTP One-Click" (RFC 8058). Please review the documentation and update the settings.') . '</p>',
+      ts('CiviMail: Enable One-Click Unsubscribe'),
+      \Psr\Log\LogLevel::NOTICE,
+      'fa-server'
+    );
+    $message->addAction(ts('Learn more'), FALSE, 'href', ['url' => 'https://civicrm.org/redirect/unsubscribe-one-click'], 'fa-info-circle');
+    $message->addAction(ts('Update settings'), FALSE, 'href', ['path' => 'civicrm/admin/mail', 'query' => 'reset=1'], 'fa-wrench');
+
+    return [$message];
+  }
+
+}
diff --git a/civicrm/CRM/Utils/Check/Message.php b/civicrm/CRM/Utils/Check/Message.php
index 8aae42516f2fe799e8f0908eb276ef019c540094..deb4a4b6cbbaba23ff7ed9a6479cfb19e353d81e 100644
--- a/civicrm/CRM/Utils/Check/Message.php
+++ b/civicrm/CRM/Utils/Check/Message.php
@@ -155,6 +155,9 @@ class CRM_Utils_Check_Message {
    *   Currently supports: api3 or href
    * @param array $params
    *   Params to be passed to CRM.api3 or CRM.url depending on type
+   *   Ex: ['MyApiEntity', 'MyApiAction', [...params...]]
+   *   Ex: ['path' => 'civicrm/admin/foo', 'query' => 'reset=1']
+   *   Ex: ['url' => 'https://example.com/more/info']
    * @param string $icon
    *   Fa-icon class for the button
    */
diff --git a/civicrm/CRM/Utils/System/Base.php b/civicrm/CRM/Utils/System/Base.php
index 8559f220b204ab7cdf1c72bcf3d1f3dcf4f9fc8e..a5cbcaf780d2317322203d0146a31794feb559de 100644
--- a/civicrm/CRM/Utils/System/Base.php
+++ b/civicrm/CRM/Utils/System/Base.php
@@ -977,7 +977,7 @@ abstract class CRM_Utils_System_Base {
       CRM_Utils_System::setHttpHeader($name, implode(', ', (array) $values));
     }
     echo $response->getBody();
-    CRM_Utils_System::civiExit();
+    CRM_Utils_System::civiExit(0, ['response' => $response]);
   }
 
   /**
diff --git a/civicrm/Civi/Test/LocalHttpClient.php b/civicrm/Civi/Test/LocalHttpClient.php
new file mode 100644
index 0000000000000000000000000000000000000000..f7e9d01da83b448bb31fc7eb74e9f5b2238b785e
--- /dev/null
+++ b/civicrm/Civi/Test/LocalHttpClient.php
@@ -0,0 +1,276 @@
+<?php
+
+namespace Civi\Test;
+
+use Civi\Test\LocalHttpClient\ClassProps;
+use Civi\Test\LocalHttpClient\SuperGlobal;
+use GuzzleHttp\Psr7\Response;
+use Psr\Http\Client\ClientInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * (Experimental) Send HTTP-style requests directly to CRM_Core_Invoke (PSR-18 ClientInterface).
+ * This allows you to process many requests within the same PHP process, which can be useful for
+ * headless unit-testing.
+ *
+ * $c = new LocalHttpClient(['reboot' => FALSE]);
+ * $response = $c->sendRequest(new Request('GET', '/civicrm/foo?reset=1&bar=100'));
+ * $response = $c->sendRequest(new Request('GET', '/civicrm/whiz?reset=1&bang=200'));
+ *
+ * In theory, this could be the basis for headless HTTP testing with client-libraries like Guzzle, Mink, or BrowserKit.
+ *
+ * WHY: CiviCRM predates the PSR HTTP OOP conventions -- many things are built with $_GET, $_REQUEST, etc.
+ * To simulate an HTTP request to these, we swap-in and swap-out values for $_GET, $_REQUEST, etc.
+ * Consequently, there is some limited isolation between the parent/requester and child/requestee.
+ *
+ * NOTE: You can improve the isolation more with `reboot=>TRUE`. This will swap (and reinitialize)
+ * the CiviCRM runtime-config and service-container. However, there is no comprehensive option to
+ * swap all static properties (other classes), so some data may still leak between requester+requestee.
+ *
+ * NOTE: This is primarily intended for use in headless testing (CIVICRM_UF=UnitTests). It may
+ * or may not be quirky with real UFs.
+ *
+ * @link https://www.php-fig.org/psr/psr-18/
+ */
+class LocalHttpClient implements ClientInterface {
+
+  /**
+   * List of scopes which should be backed-up, (re)populated, (re)set for the duration of the subrequest.
+   *
+   * @var array
+   *   Ex: ['_GET' => new SuperGlobal('_GET')]
+   */
+  protected $scopes;
+
+  /**
+   * List of scopes which should be inherited/extended within the subrequest.
+   *
+   * @var array
+   *   Ex: ['_COOKIE', '_SERVER']
+   */
+  protected $inherit;
+
+  /**
+   * Whether to generate the HTML <HEAD>er
+   *
+   * @var bool
+   */
+  protected $htmlHeader;
+
+  /**
+   * @param array $options
+   *   - reboot (bool): TRUE if you want to re-bootstrap CiviCRM (config/container) on each request
+   *     Default: FALSE
+   *   - htmlHeader (bool): TRUE if you want the generated page to include the full HTML header
+   *     This may become standard (non-optional). It's opt-out to help debug/work-around some early
+   *     quirks when first using LocalHttpClient in CI.
+   *   - globals (string[]): List of (super)globals that should be backed-up, populated, used, and restored.
+   *     Default: ['_GET', '_POST', '_COOKIE', '_FILES', '_SERVER', '_REQUEST']
+   *   - inherit (string[]): When populating these (super)globals, build on top of the existing values.
+   *     Default: ['_COOKIE', '_SERVER']
+   */
+  public function __construct(array $options = []) {
+    $defaultOptions = [
+      'reboot' => FALSE,
+      'htmlHeader' => TRUE,
+      'globals' => ['_GET', '_POST', '_COOKIE', '_FILES', '_SERVER', '_REQUEST'],
+      'inherit' => ['_COOKIE', '_SERVER'],
+    ];
+    $options = array_merge($defaultOptions, $options);
+
+    $this->inherit = $options['inherit'];
+    $this->htmlHeader = $options['htmlHeader'];
+    $this->scopes = [];
+
+    foreach ($options['globals'] as $scopeName) {
+      $this->scopes[$scopeName] = new SuperGlobal($scopeName);
+    }
+
+    if ($options['reboot']) {
+      $classes = [
+        \Civi::class,
+        \CRM_Core_Config::class,
+        \CRM_Utils_Hook::class,
+        \Civi\Core\Resolver::class,
+        \CRM_Queue_Service::class,
+        \CRM_Utils_System::class,
+        \CRM_Utils_Cache::class,
+      ];
+      foreach ($classes as $class) {
+        $this->scopes[$class] = new ClassProps($class);
+      }
+    }
+  }
+
+  public function sendRequest(RequestInterface $request): ResponseInterface {
+    $backup = $this->getAllValues();
+    try {
+      $this->initScopes($request);
+
+      $var = \CRM_Core_Config::singleton()->userFrameworkURLVar;
+      if (!isset($_GET[$var])) {
+        $_GET[$var] = ltrim($request->getUri()->getPath(), '/');
+      }
+      $body = $this->invoke($_GET[$var]);
+      // FIXME: There's probably a way to instrument CRM_Utils_System_UnitTests to do this better.
+      return new Response(200, [], $body);
+    }
+    catch (\CRM_Core_Exception_PrematureExitException $e) {
+      if (isset($e->errorData['response'])) {
+        return $e->errorData['response'];
+      }
+      // FIXME: There are some things which emit PrematureExitException but don't provide the $response object.
+      // We should probably revise \CRM_Utils_System::redirect() and returnJsonResponse()
+      else {
+        throw $e;
+      }
+    }
+    finally {
+      $this->restoreAllValues($backup);
+    }
+  }
+
+  protected function initScopes(RequestInterface $request) {
+    foreach ($this->scopes as $scopeName => $scope) {
+      if (!in_array($scopeName, $this->inherit)) {
+        $scope->unsetKeys(array_keys($scope->getValues()));
+      }
+
+      $method = 'initValues' . $scopeName;
+      $initValues = is_callable([$this, $method]) ? $this->$method($request) : [];
+      $scope->setValues($initValues);
+    }
+    if (in_array('CRM_Core_Config', $this->scopes)) {
+      \CRM_Core_Config::singleton();
+    }
+  }
+
+  /**
+   * Map data from the request to $_GET.
+   *
+   * @param \Psr\Http\Message\RequestInterface $request
+   * @return array
+   */
+  protected function initValues_GET(RequestInterface $request): array {
+    $result = [];
+    parse_str($request->getUri()->getQuery() ?: '', $result);
+    return $result;
+  }
+
+  /**
+   * Map data from the request to $_POST.
+   *
+   * @param \Psr\Http\Message\RequestInterface $request
+   * @return array
+   */
+  protected function initValues_POST(RequestInterface $request): array {
+    $result = [];
+    if ($request->getMethod() === 'POST') {
+      $contentTypes = $request->getHeader('Content-Type');
+      if (in_array('application/x-www-form-urlencoded', $contentTypes) || empty($contentTypes)) {
+        $body = (string) $request->getBody();
+        parse_str($body, $result);
+      }
+    }
+    return $result;
+  }
+
+  /**
+   * Map data from the request to $_REQUEST.
+   *
+   * @param \Psr\Http\Message\RequestInterface $request
+   * @return array
+   */
+  protected function initValues_REQUEST(RequestInterface $request): array {
+    $sources = ['g' => '_GET', 'p' => '_POST', 'c' => '_COOKIE'];
+
+    if (ini_get('request_order')) {
+      $order = strtolower(ini_get('request_order'));
+    }
+    elseif (ini_get('variables_order')) {
+      $order = strtolower(ini_get('variables_order'));
+    }
+    else {
+      $order = 'gpc';
+    }
+
+    $result = [];
+    for ($i = 0; $i < strlen($order); $i++) {
+      if (isset($sources[$order[$i]])) {
+        $scope = $this->scopes[$sources[$order[$i]]];
+        $result = array_merge($result, $scope->getValues());
+      }
+    }
+    return $result;
+  }
+
+  protected function initValues_SERVER(RequestInterface $request): array {
+    $uri = $request->getUri();
+
+    $result = [];
+    $result['REQUEST_METHOD'] = $request->getMethod();
+    $result['REQUEST_URI'] = $uri->getPath();
+    if ($uri->getQuery()) {
+      $result['REQUEST_URI'] .= '?' . $uri->getQuery();
+    }
+    if ($uri->getHost()) {
+      $result['HTTP_HOST'] = $uri->getHost();
+      if ($uri->getPort()) {
+        $result['HTTP_HOST'] .= ':' . $uri->getPort();
+        $result['SERVER_PORT'] = $uri->getPort();
+      }
+      $result['SERVER_NAME'] = $uri->getHost();
+    }
+    $result['HTTP_USER_AGENT'] = __CLASS__;
+    return $result;
+  }
+
+  protected function invoke(string $route): ?string {
+    if ($this->htmlHeader) {
+      \CRM_Core_Resources::singleton()->addCoreResources('html-header');
+    }
+
+    ob_start();
+    try {
+      $pageContent = \CRM_Core_Invoke::_invoke(explode('/', $route));
+    }
+    finally {
+      $printedContent = ob_get_clean();
+    }
+
+    if (empty($pageContent) && !empty($printedContent)) {
+      $pageContent = $printedContent;
+    }
+
+    $locale = \CRM_Core_I18n::getLocale();
+    $lang = substr($locale, 0, 2);
+    $dir = \CRM_Core_I18n::isLanguageRTL($locale) ? 'rtl' : 'ltr';
+    $head = $this->htmlHeader ? \CRM_Core_Region::instance('html-header')->render('') : '';
+
+    return <<<PAGETPL
+<!DOCTYPE html>
+<html lang="$lang" dir="$dir">
+<head>$head</head>
+<body class="civicrm-unittest-body">$pageContent</body>
+</html>
+PAGETPL;
+  }
+
+  public function getAllValues(): array {
+    $backup = [];
+    foreach ($this->scopes as $scopeName => $scope) {
+      $backup[$scopeName] = $scope->getValues();
+    }
+    return $backup;
+  }
+
+  protected function restoreAllValues(array &$backup): void {
+    foreach ($this->scopes as $scopeName => $scope) {
+      $extraKeys = array_diff(array_keys($scope->getValues()), array_keys($backup[$scopeName]));
+      $scope->unsetKeys($extraKeys);
+      $scope->setValues($backup[$scopeName]);
+    }
+  }
+
+}
diff --git a/civicrm/Civi/Test/LocalHttpClient/ClassProps.php b/civicrm/Civi/Test/LocalHttpClient/ClassProps.php
new file mode 100644
index 0000000000000000000000000000000000000000..736c18ffdd0bed3293dc7fd0b50db31e9a36a1ed
--- /dev/null
+++ b/civicrm/Civi/Test/LocalHttpClient/ClassProps.php
@@ -0,0 +1,40 @@
+<?php
+namespace Civi\Test\LocalHttpClient;
+
+use Civi\Test\Invasive;
+
+/**
+ * @internal
+ */
+class ClassProps {
+
+  /**
+   * @var \ReflectionClass
+   */
+  protected $class;
+
+  public function __construct(string $class) {
+    $this->class = new \ReflectionClass($class);
+  }
+
+  public function getValues() {
+    return $this->class->getStaticProperties() ?: [];
+  }
+
+  public function setValues(iterable $values): void {
+    foreach ($values as $key => $value) {
+      // In PHP 7.3, setStaticPropertyValue() fails for private properties.
+      // $this->class->setStaticPropertyValue($key, $value);
+      Invasive::set([$this->class->getName(), $key], $value);
+    }
+  }
+
+  public function unsetKeys(iterable $keys): void {
+    foreach ($keys as $key) {
+      // In PHP 7.3, setStaticPropertyValue() fails for private properties.
+      // $this->class->setStaticPropertyValue($key, NULL);
+      Invasive::set([$this->class->getName(), $key], NULL);
+    }
+  }
+
+}
diff --git a/civicrm/Civi/Test/LocalHttpClient/SuperGlobal.php b/civicrm/Civi/Test/LocalHttpClient/SuperGlobal.php
new file mode 100644
index 0000000000000000000000000000000000000000..437f10af1eec0437161cea50fdcde80c55cbc7f7
--- /dev/null
+++ b/civicrm/Civi/Test/LocalHttpClient/SuperGlobal.php
@@ -0,0 +1,37 @@
+<?php
+namespace Civi\Test\LocalHttpClient;
+
+/**
+ * @internal
+ */
+class SuperGlobal {
+
+  /**
+   * @var string
+   */
+  protected $name;
+
+  /**
+   * @param string $name
+   */
+  public function __construct(string $name) {
+    $this->name = $name;
+  }
+
+  public function getValues() {
+    return $GLOBALS[$this->name];
+  }
+
+  public function setValues(iterable $values): void {
+    foreach ($values as $key => $value) {
+      $GLOBALS[$this->name][$key] = $value;
+    }
+  }
+
+  public function unsetKeys(iterable $keys): void {
+    foreach ($keys as $key) {
+      unset($GLOBALS[$this->name][$key]);
+    }
+  }
+
+}
diff --git a/civicrm/ang/crmStatusPage/StatusPageCtrl.js b/civicrm/ang/crmStatusPage/StatusPageCtrl.js
index 5dad04fc593c67f282ce5bcd62909ca057144ebc..2d6d75f61ffa21cb003e83ebd96f1ed1134c8d25 100644
--- a/civicrm/ang/crmStatusPage/StatusPageCtrl.js
+++ b/civicrm/ang/crmStatusPage/StatusPageCtrl.js
@@ -51,7 +51,7 @@
         function run() {
           switch (action.type) {
             case 'href':
-              window.location = CRM.url(action.params.path, action.params.query, action.params.mode);
+              window.location = action.params.url ? action.params.url : CRM.url(action.params.path, action.params.query, action.params.mode);
               break;
 
             case 'api3':
diff --git a/civicrm/civicrm-version.php b/civicrm/civicrm-version.php
index 803b1543824ef159c51c65fed22f587d4e313694..362820b04172039adb00f8ca1ee019cab0f8b701 100644
--- a/civicrm/civicrm-version.php
+++ b/civicrm/civicrm-version.php
@@ -1,7 +1,7 @@
 <?php
 /** @deprecated */
 function civicrmVersion( ) {
-  return array( 'version'  => '5.69.2',
+  return array( 'version'  => '5.69.3',
                 'cms'      => 'Wordpress',
                 'revision' => '' );
 }
diff --git a/civicrm/ext/afform/admin/info.xml b/civicrm/ext/afform/admin/info.xml
index fd44926b3d3e2796cf86c651a1cef97bf9e71b37..3762b1ff97e1827a48d491a46801f78b58c0702d 100644
--- a/civicrm/ext/afform/admin/info.xml
+++ b/civicrm/ext/afform/admin/info.xml
@@ -12,8 +12,8 @@
     <url desc="Chat">https://chat.civicrm.org/civicrm/channels/dev-afform</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>beta</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/afform/core/info.xml b/civicrm/ext/afform/core/info.xml
index 5a8c0e747b0b3df93934c9ad59275e8b692dcffb..fcf0b28f5ebbadc4df4d89aea5aad1e20c94fe8a 100644
--- a/civicrm/ext/afform/core/info.xml
+++ b/civicrm/ext/afform/core/info.xml
@@ -12,8 +12,8 @@
     <url desc="Chat">https://chat.civicrm.org/civicrm/channels/dev-afform</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <compatibility>
     <ver>5.69</ver>
   </compatibility>
diff --git a/civicrm/ext/afform/html/info.xml b/civicrm/ext/afform/html/info.xml
index 3c4f105ab2556a40345362073ab19821cab73944..dada7a31a770efe0f6c684bc12a3e53d89d2f8ca 100644
--- a/civicrm/ext/afform/html/info.xml
+++ b/civicrm/ext/afform/html/info.xml
@@ -12,8 +12,8 @@
     <url desc="Chat">https://chat.civicrm.org/civicrm/channels/dev-afform</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>alpha</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/afform/mock/info.xml b/civicrm/ext/afform/mock/info.xml
index ac698c472776828a547c072ef481d9f1119a73a7..795b1781026ab27757cf4848419cc08e6e572a96 100644
--- a/civicrm/ext/afform/mock/info.xml
+++ b/civicrm/ext/afform/mock/info.xml
@@ -11,8 +11,8 @@
   <urls>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <tags>
     <tag>mgmt:hidden</tag>
   </tags>
diff --git a/civicrm/ext/authx/info.xml b/civicrm/ext/authx/info.xml
index 921c9e6f18348e49d5f6dc851686d7561a052675..5f0ef54f69408e956af8017ff2bafb1dcb54449e 100644
--- a/civicrm/ext/authx/info.xml
+++ b/civicrm/ext/authx/info.xml
@@ -14,8 +14,8 @@
     <url desc="Issues">https://lab.civicrm.org/dev/core/-/issues</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>mgmt:required</tag>
diff --git a/civicrm/ext/civi_campaign/info.xml b/civicrm/ext/civi_campaign/info.xml
index a8a9372e666a1b6a7b6a610a9beaeb0e01d3a8d5..355cf41c727f8fd2fde067ce714ee3e247b5e8c7 100644
--- a/civicrm/ext/civi_campaign/info.xml
+++ b/civicrm/ext/civi_campaign/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/campaign/what-is-civicampaign/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civi_case/info.xml b/civicrm/ext/civi_case/info.xml
index e0fd52eb2d4817c1953198fe3f8ecbd20faa799f..f2a0fff4c2bbc8981efbc8431055ddc5fd96cf83 100644
--- a/civicrm/ext/civi_case/info.xml
+++ b/civicrm/ext/civi_case/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/case-management/what-is-civicase/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civi_contribute/info.xml b/civicrm/ext/civi_contribute/info.xml
index 3f201436df311540e38a9d4b3fffe1e6014e7a2c..f01beb69249a1a8034286b15e62624fbe05046f3 100644
--- a/civicrm/ext/civi_contribute/info.xml
+++ b/civicrm/ext/civi_contribute/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/contributions/what-is-civicontribute/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civi_event/info.xml b/civicrm/ext/civi_event/info.xml
index 7185d36e42baed763e7091b20958b575126229da..ffcd3900c57d05b76e27b4be03af792a803f4bd9 100644
--- a/civicrm/ext/civi_event/info.xml
+++ b/civicrm/ext/civi_event/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/events/what-is-civievent</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civi_mail/info.xml b/civicrm/ext/civi_mail/info.xml
index e03fb4c40aa7acd24a67127ce1a685dda81674cb..aa0114e164495c6661b4f29dd317ec0caea0dc1e 100644
--- a/civicrm/ext/civi_mail/info.xml
+++ b/civicrm/ext/civi_mail/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/email/what-is-civimail/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civi_member/info.xml b/civicrm/ext/civi_member/info.xml
index 1f78fd8167296988af3afd12763e3d41bc6ee97a..4499c7671b4fe5c20c819dd33164502d94ba188d 100644
--- a/civicrm/ext/civi_member/info.xml
+++ b/civicrm/ext/civi_member/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/membership/what-is-civimember/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civi_pledge/info.xml b/civicrm/ext/civi_pledge/info.xml
index a8ab9b1279b68260867d7e3e2fdad6c0f50f588a..bb400f8b5f3645272388806c921ce14305efe9fe 100644
--- a/civicrm/ext/civi_pledge/info.xml
+++ b/civicrm/ext/civi_pledge/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/pledges/what-is-civipledge/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civi_report/info.xml b/civicrm/ext/civi_report/info.xml
index e42793d098ff00b934e5affeaed22395348199b6..b9fa72fcf4a486bae8e6642c73bd3a5036737f11 100644
--- a/civicrm/ext/civi_report/info.xml
+++ b/civicrm/ext/civi_report/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/reporting/what-is-civireport/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>component</tag>
diff --git a/civicrm/ext/civicrm_admin_ui/info.xml b/civicrm/ext/civicrm_admin_ui/info.xml
index 42da1f2468fb61cd561322a6a1e59f03fa1f1663..df1c2c867cd14805f1909978036919e1017b9753 100644
--- a/civicrm/ext/civicrm_admin_ui/info.xml
+++ b/civicrm/ext/civicrm_admin_ui/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://lab.civicrm.org/dev/core/-/issues</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>beta</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/civicrm_search_ui/info.xml b/civicrm/ext/civicrm_search_ui/info.xml
index 55908928e790e9a66eef8aee663dc2abd8962153..f025e92455e19da58143d855dab9a8bf798a0c73 100644
--- a/civicrm/ext/civicrm_search_ui/info.xml
+++ b/civicrm/ext/civicrm_search_ui/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://lab.civicrm.org/dev/core/-/issues</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>alpha</develStage>
   <requires>
     <ext>org.civicrm.search_kit</ext>
diff --git a/civicrm/ext/civigrant/info.xml b/civicrm/ext/civigrant/info.xml
index a8a22d1c3788825a5c1238e01beb721a59b72ce5..f66d8f9941fe73685b14186388f0d1c8bc12883e 100644
--- a/civicrm/ext/civigrant/info.xml
+++ b/civicrm/ext/civigrant/info.xml
@@ -12,8 +12,8 @@
     <url desc="Documentation">https://docs.civicrm.org/user/en/latest/grants/what-is-civigrant/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/civiimport/info.xml b/civicrm/ext/civiimport/info.xml
index af06112910f8467985284650c5b3056189e41037..968163f3726ad5ac0dad63b048627936f1c20874 100644
--- a/civicrm/ext/civiimport/info.xml
+++ b/civicrm/ext/civiimport/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://civicrm.org</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>alpha</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/ckeditor4/info.xml b/civicrm/ext/ckeditor4/info.xml
index e619949d1c62214f04d1bd89197420e15e3d5dcb..b1a57717b6b2329586c7b62e4353b0f82a8d3a0f 100644
--- a/civicrm/ext/ckeditor4/info.xml
+++ b/civicrm/ext/ckeditor4/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://github.com/civicrm/civicrm-core/</url>
     <url desc="Licensing">https://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/contributioncancelactions/info.xml b/civicrm/ext/contributioncancelactions/info.xml
index 675f8d2c67b6e6a4a4b93417c2d286087926c530..25113898e1edb953826f1d23cdd909829d8b6fed 100644
--- a/civicrm/ext/contributioncancelactions/info.xml
+++ b/civicrm/ext/contributioncancelactions/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://civicrm.org</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/elavon/info.xml b/civicrm/ext/elavon/info.xml
index bd9b0fdddc6e865d832aba2ac628832dd1e344a4..b1c63a816a575fccfc6435a2d920f49337397c85 100644
--- a/civicrm/ext/elavon/info.xml
+++ b/civicrm/ext/elavon/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://lab.civicrm.org</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/eventcart/info.xml b/civicrm/ext/eventcart/info.xml
index 381bb5b05dad042ee979e8b052fa969bb613d165..7df0d6a3b48b5cbdff5e135e021ecefa46f4da90 100644
--- a/civicrm/ext/eventcart/info.xml
+++ b/civicrm/ext/eventcart/info.xml
@@ -12,8 +12,8 @@
     <url desc="Main Extension Page">https://github.com/civicrm/civicrm-core/tree/master/ext/eventcart</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <tags>
     <tag>mgmt:hidden</tag>
   </tags>
diff --git a/civicrm/ext/ewaysingle/info.xml b/civicrm/ext/ewaysingle/info.xml
index 2d2bf431b60d44359a63d98e4819e3a628330478..99447186b4e1122786307320dcb862a2938ac0ae 100644
--- a/civicrm/ext/ewaysingle/info.xml
+++ b/civicrm/ext/ewaysingle/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://github.com/civicrm/civicrm-core/blob/master/ext/ewaysingle</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <tags>
     <tag>mgmt:hidden</tag>
   </tags>
diff --git a/civicrm/ext/financialacls/info.xml b/civicrm/ext/financialacls/info.xml
index 3dc506da21354be7776d7124cb838e0d9b555976..e2d4b8dfab796da2bdd22bad928b8a320938044f 100644
--- a/civicrm/ext/financialacls/info.xml
+++ b/civicrm/ext/financialacls/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://FIXME</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/flexmailer/info.xml b/civicrm/ext/flexmailer/info.xml
index 1fc9314c69ade4b561566fe400fbfea28736666c..036f9bb28d766e2f72489d3244cc5a520b87e1a4 100644
--- a/civicrm/ext/flexmailer/info.xml
+++ b/civicrm/ext/flexmailer/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://civicrm.stackexchange.com/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <comments>
     FlexMailer is an email delivery engine which replaces the internal guts
diff --git a/civicrm/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php b/civicrm/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php
index d91e6ec490cc4beaa9c7d20c7e5bf5ac97787e32..679b4b6426a294307652fb5ce7ac283196b7fdc3 100644
--- a/civicrm/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php
+++ b/civicrm/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php
@@ -75,13 +75,13 @@ class FlexMailerSystemTest extends \CRM_Mailing_BaseMailingSystemTest {
    * @see CRM_Utils_Hook::alterMailParams
    */
   public function hook_alterMailParams(&$params, $context = NULL) {
-    $this->counts['hook_alterMailParams'] = 1;
-    $this->assertEquals('flexmailer', $context);
+    $this->counts["hook_alterMailParams::$context"] = 1;
   }
 
   public function tearDown(): void {
     parent::tearDown();
-    $this->assertNotEmpty($this->counts['hook_alterMailParams']);
+    $this->assertNotEmpty($this->counts['hook_alterMailParams::flexmailer']);
+    $this->assertEmpty($this->counts['hook_alterMailParams::civimail'] ?? NULL);
     foreach (FlexMailer::getEventTypes() as $event => $class) {
       $this->assertTrue(
         $this->counts[$class] > 0,
diff --git a/civicrm/ext/greenwich/info.xml b/civicrm/ext/greenwich/info.xml
index 475525e8ec0966e27689bdf4cbf7be407ccac828..15b35f61e5b5e9d9b8bc18dd2aeca6f87bf6e17c 100644
--- a/civicrm/ext/greenwich/info.xml
+++ b/civicrm/ext/greenwich/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://civicrm.org</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <tags>
     <tag>mgmt:hidden</tag>
   </tags>
diff --git a/civicrm/ext/legacycustomsearches/info.xml b/civicrm/ext/legacycustomsearches/info.xml
index 7ff4a1d888880d5e4317f72c9bca212d0fdb8ac8..3948283af235948dcd8de6e5422222bdbb441ac1 100644
--- a/civicrm/ext/legacycustomsearches/info.xml
+++ b/civicrm/ext/legacycustomsearches/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://FIXME</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/message_admin/info.xml b/civicrm/ext/message_admin/info.xml
index f72d3766cfa1a73962e6e7b4f94eceb3111557df..b8bd023d17f463336f1d482f63164293b216987c 100644
--- a/civicrm/ext/message_admin/info.xml
+++ b/civicrm/ext/message_admin/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://civicrm.org</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>alpha</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/oauth-client/info.xml b/civicrm/ext/oauth-client/info.xml
index 22c8170196ba5f3220a5fbbef233419e6766ce7c..e8e73931d51b412ca20bf91727f718aa741b056e 100644
--- a/civicrm/ext/oauth-client/info.xml
+++ b/civicrm/ext/oauth-client/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://lab.civicrm.org/dev/core/-/issues</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/payflowpro/info.xml b/civicrm/ext/payflowpro/info.xml
index d49749d23b14e22c2d1b1f8c1fa923190474bd6a..5d9b36d5cb45c6a115df0b7d158faf51524cb00a 100644
--- a/civicrm/ext/payflowpro/info.xml
+++ b/civicrm/ext/payflowpro/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://lab.civicrm.org</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/recaptcha/info.xml b/civicrm/ext/recaptcha/info.xml
index 9d82903a1e35008f205c8cfc4139a079856db941..548b52d5f030c199ba75a82f5a763641cdab73ed 100644
--- a/civicrm/ext/recaptcha/info.xml
+++ b/civicrm/ext/recaptcha/info.xml
@@ -12,8 +12,8 @@
     <url desc="Main Extension Page">https://github.com/civicrm/civicrm-core/tree/master/ext/recaptcha</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <tags>
     <tag>mgmt:hidden</tag>
   </tags>
diff --git a/civicrm/ext/scheduled_communications/info.xml b/civicrm/ext/scheduled_communications/info.xml
index 7750124795ce5c74c7ef33fe869485189f55a01f..4659c4d5f7ab75cab2e726b3a79d808eb11585b4 100644
--- a/civicrm/ext/scheduled_communications/info.xml
+++ b/civicrm/ext/scheduled_communications/info.xml
@@ -12,8 +12,8 @@
     <url desc="Chat">https://chat.civicrm.org/civicrm/channels/search-improvements</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>beta</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/search_kit/info.xml b/civicrm/ext/search_kit/info.xml
index f9071bcb4011a5eb3a6dd6adcc51b80907af9e25..b64fb79767f781c585ea24b274e8cbec2ffbb53d 100644
--- a/civicrm/ext/search_kit/info.xml
+++ b/civicrm/ext/search_kit/info.xml
@@ -14,8 +14,8 @@
     <url desc="Issues">https://lab.civicrm.org/dev/report/-/issues</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>stable</develStage>
   <tags>
     <tag>mgmt:required</tag>
diff --git a/civicrm/ext/sequentialcreditnotes/info.xml b/civicrm/ext/sequentialcreditnotes/info.xml
index c1abec7e72e0d33fcfad57f97943579da8b13864..b64cbf4cfe22cd6776b59cc0d6c08ab0c16546d0 100644
--- a/civicrm/ext/sequentialcreditnotes/info.xml
+++ b/civicrm/ext/sequentialcreditnotes/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">https://lab.civicrm.org/extensions/sequentialcreditnotes</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <tags>
     <tag>mgmt:hidden</tag>
   </tags>
diff --git a/civicrm/ext/standaloneusers/info.xml b/civicrm/ext/standaloneusers/info.xml
index 03439363c63d5ad0511e2d4783d0febf922ab0eb..083bf03bab1cee115ba4aecc4c0bff698388efa2 100644
--- a/civicrm/ext/standaloneusers/info.xml
+++ b/civicrm/ext/standaloneusers/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://FIXME</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>alpha</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/ext/user_dashboard/info.xml b/civicrm/ext/user_dashboard/info.xml
index c587ec60566fbec314dac7854125196fc4c633f7..20b53aa576cdb73397a36dd1fd9596f7c8395a2d 100644
--- a/civicrm/ext/user_dashboard/info.xml
+++ b/civicrm/ext/user_dashboard/info.xml
@@ -14,8 +14,8 @@
     <url desc="Support">http://FIXME</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2024-01-11</releaseDate>
-  <version>5.69.2</version>
+  <releaseDate>2024-01-25</releaseDate>
+  <version>5.69.3</version>
   <develStage>alpha</develStage>
   <compatibility>
     <ver>5.69</ver>
diff --git a/civicrm/js/version.json b/civicrm/js/version.json
index 01750314f6d7e14f167dc4328b77add48ee53d9a..ff623e264c167a92b79857667496a47307dd555a 100644
--- a/civicrm/js/version.json
+++ b/civicrm/js/version.json
@@ -1 +1 @@
-"5.69.2"
+"5.69.3"
diff --git a/civicrm/release-notes.md b/civicrm/release-notes.md
index 7729a3d403c962eb622a84736689ec24c976d78d..75fc12be419f11576c2206c87f1cdfad817668dd 100644
--- a/civicrm/release-notes.md
+++ b/civicrm/release-notes.md
@@ -15,6 +15,15 @@ Other resources for identifying changes are:
     * https://github.com/civicrm/civicrm-joomla
     * https://github.com/civicrm/civicrm-wordpress
 
+## CiviCRM 5.69.3
+
+Released January 26, 2024
+
+- **[Synopsis](release-notes/5.69.3.md#synopsis)**
+- **[Bugs resolved](release-notes/5.69.3.md#bugs)**
+- **[Credits](release-notes/5.69.3.md#credits)**
+- **[Feedback](release-notes/5.69.3.md#feedback)**
+
 ## CiviCRM 5.69.2
 
 Released January 11, 2024
diff --git a/civicrm/release-notes/5.69.3.md b/civicrm/release-notes/5.69.3.md
new file mode 100644
index 0000000000000000000000000000000000000000..ac4014acd1a9efc4322fe8e823d8f203fecb76c4
--- /dev/null
+++ b/civicrm/release-notes/5.69.3.md
@@ -0,0 +1,49 @@
+# CiviCRM 5.69.3
+
+Released January 26, 2024
+
+- **[Synopsis](#synopsis)**
+- **[Bugs resolved](#bugs)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |          |
+| --------------------------------------------------------------- | -------- |
+| Change the database schema?                                     | no       |
+| Alter the API?                                                  | no       |
+| **Require attention to configuration options?**                 | **yes**  |
+| Fix problems installing or upgrading to a previous version?     | no       |
+| **Introduce features?**                                         | **yes**  |
+| **Fix bugs?**                                                   | **yes**  |
+| Fix security vulnerabilities?                                   | no       |
+
+## <a name="bugs"></a>Bugs resolved
+
+* **_CiviMail_: Add support for "HTTP One-Click" unsubscribes ([dev/core#4641](https://lab.civicrm.org/dev/core/-/issues/4641): [#28964](https://github.com/civicrm/civicrm-core/pull/28964), [#29086](https://github.com/civicrm/civicrm-core/pull/29086))**
+
+  CiviMail users with large mailing lists should consider enabling this new option. [More info](https://civicrm.org/redirect/unsubscribe-one-click)
+
+* **_CiviContribute_: Fix error viewing contributions when "Tax and Invoicing" is enabled ([#28994](https://github.com/civicrm/civicrm-core/pull/28994), [#29000](https://github.com/civicrm/civicrm-core/pull/29000))**
+* **_CiviContribute_: Fix focus-handling for "Other Amount"  ([dev/core#4912](https://lab.civicrm.org/dev/core/-/issues/4912): [#29016](https://github.com/civicrm/civicrm-core/pull/29016))**
+* **_CiviMember_: Fix handling of "Auto Renew" checkbox in certain configurations ([#29069](https://github.com/civicrm/civicrm-core/pull/29069))**
+* **_Custom Fields_: Fix for custom fields when creating new (subtyped) contacts ([dev/core#4910](https://lab.civicrm.org/dev/core/-/issues/4910): [#29003](https://github.com/civicrm/civicrm-core/pull/29003))**
+* **_PHP 7.3_: Restore compatibility with PHP 7.3 ([#29074](https://github.com/civicrm/civicrm-core/pull/29074))**
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following authors and reviewers:
+
+Wikimedia Foundation - Eileen McNaughton; tresero; Tadpole Collective - Kevin Cristiano;
+Skvare - Mark Hanna; pbarmak; Megaphone Technology Consulting - Jon Goldberg; Makoa - Usha
+F. Matisson; lkuttner; JMA Consulting - Seamus Lee; iank; Humanists UK - Andrew West;;
+Fuzion - Peter Davis; Dave D; Coop SymbioTIC - Shane Bill; CiviDesk - Yashodha Chaku;
+CiviCRM - Tim Otten, Coleman Watts, Josh Gowans; Christian Wach; Chabadrichmond;
+Australian Greens - John Twyman; Artful Robot - Rich Lott; Agileware - Justin Freeman
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Tim Otten and Andie Hunt.  If you'd like to
+provide feedback on them, please login to https://chat.civicrm.org/civicrm and
+contact `@agh1`.
diff --git a/civicrm/settings/Mailing.setting.php b/civicrm/settings/Mailing.setting.php
index d000dc47fda603680beeee9f0a5385fcedc54b50..15e127bce968c8fc520b16b7a8f3a5cbc9d67a32 100644
--- a/civicrm/settings/Mailing.setting.php
+++ b/civicrm/settings/Mailing.setting.php
@@ -18,6 +18,8 @@
  * Settings metadata file
  */
 
+$unsubLearnMore = '<br/>' . ts('(<a %1">Learn more</a>)', [1 => 'href="https://civicrm.org/redirect/unsubscribe-one-click" target="_blank"']);
+
 return [
   'profile_double_optin' => [
     'group_name' => 'Mailing Preferences',
@@ -91,6 +93,28 @@ return [
     'is_contact' => 0,
     'help_text' => NULL,
   ],
+  'civimail_unsubscribe_methods' => [
+    'group_name' => 'Mailing Preferences',
+    'group' => 'mailing',
+    'name' => 'civimail_unsubscribe_methods',
+    'type' => 'Array',
+    'quick_form_type' => 'Select',
+    'html_type' => 'Select',
+    'html_attributes' => [
+      'multiple' => 1,
+      'class' => 'crm-select2',
+    ],
+    'default' => version_compare(CRM_Utils_System::version(), '5.72', '<=') ? ['mailto'] : ['mailto', 'http', 'oneclick'],
+    'add' => '5.69',
+    'title' => ts('Unsubscribe Methods'),
+    'is_domain' => 1,
+    'is_contact' => 0,
+    'description' => ts("These methods will be offered to email clients for semi-automated unsubscribes. Support for each depends on the recipient's email client.") . $unsubLearnMore,
+    'help_text' => NULL,
+    'pseudoconstant' => [
+      'callback' => 'CRM_Mailing_Service_ListUnsubscribe::getMethods',
+    ],
+  ],
   'replyTo' => [
     'group_name' => 'Mailing Preferences',
     'group' => 'mailing',
diff --git a/civicrm/sql/civicrm_data.mysql b/civicrm/sql/civicrm_data.mysql
index 4c73ac30404b346f4216a0058db4aeaae85542ed..d77cb76bf3a90867f4c0cd44e3e913bc30e4fd2e 100644
--- a/civicrm/sql/civicrm_data.mysql
+++ b/civicrm/sql/civicrm_data.mysql
@@ -21703,4 +21703,4 @@ INSERT INTO `civicrm_report_instance`
     ( `domain_id`, `title`, `report_id`, `description`, `permission`, `form_values`)
 VALUES
     (  @domainID, 'Survey Details', 'survey/detail', 'Detailed report for canvassing, phone-banking, walk lists or other surveys.', 'access CiviReport', 'a:39:{s:6:"fields";a:2:{s:9:"sort_name";s:1:"1";s:6:"result";s:1:"1";}s:22:"assignee_contact_id_op";s:2:"eq";s:25:"assignee_contact_id_value";s:0:"";s:12:"sort_name_op";s:3:"has";s:15:"sort_name_value";s:0:"";s:17:"street_number_min";s:0:"";s:17:"street_number_max";s:0:"";s:16:"street_number_op";s:3:"lte";s:19:"street_number_value";s:0:"";s:14:"street_name_op";s:3:"has";s:17:"street_name_value";s:0:"";s:15:"postal_code_min";s:0:"";s:15:"postal_code_max";s:0:"";s:14:"postal_code_op";s:3:"lte";s:17:"postal_code_value";s:0:"";s:7:"city_op";s:3:"has";s:10:"city_value";s:0:"";s:20:"state_province_id_op";s:2:"in";s:23:"state_province_id_value";a:0:{}s:13:"country_id_op";s:2:"in";s:16:"country_id_value";a:0:{}s:12:"survey_id_op";s:2:"in";s:15:"survey_id_value";a:0:{}s:12:"status_id_op";s:2:"eq";s:15:"status_id_value";s:1:"1";s:11:"custom_1_op";s:2:"in";s:14:"custom_1_value";a:0:{}s:11:"custom_2_op";s:2:"in";s:14:"custom_2_value";a:0:{}s:17:"custom_3_relative";s:1:"0";s:13:"custom_3_from";s:0:"";s:11:"custom_3_to";s:0:"";s:11:"description";s:75:"Detailed report for canvassing, phone-banking, walk lists or other surveys.";s:13:"email_subject";s:0:"";s:8:"email_to";s:0:"";s:8:"email_cc";s:0:"";s:10:"permission";s:17:"access CiviReport";s:6:"groups";s:0:"";s:9:"domain_id";i:1;}');
-UPDATE civicrm_domain SET version = '5.69.2';
+UPDATE civicrm_domain SET version = '5.69.3';
diff --git a/civicrm/sql/civicrm_generated.mysql b/civicrm/sql/civicrm_generated.mysql
index a70d269fee746751cb78163534b09b09bdbea27a..0246c63aed56e2cb1de3b541c5a8138f8dfaa048 100644
--- a/civicrm/sql/civicrm_generated.mysql
+++ b/civicrm/sql/civicrm_generated.mysql
@@ -2976,7 +2976,7 @@ UNLOCK TABLES;
 LOCK TABLES `civicrm_domain` WRITE;
 /*!40000 ALTER TABLE `civicrm_domain` DISABLE KEYS */;
 INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES
- (1,'Default Domain Name',NULL,'5.69.2',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
+ (1,'Default Domain Name',NULL,'5.69.3',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
 /*!40000 ALTER TABLE `civicrm_domain` ENABLE KEYS */;
 UNLOCK TABLES;
 
diff --git a/civicrm/templates/CRM/Contribute/Form/Contribution/Main.tpl b/civicrm/templates/CRM/Contribute/Form/Contribution/Main.tpl
index 84f8490e06353920d35c658b0acd001756455928..d44bd2b60028e7763084cab804f3d15ac7708f06 100644
--- a/civicrm/templates/CRM/Contribute/Form/Contribution/Main.tpl
+++ b/civicrm/templates/CRM/Contribute/Form/Contribution/Main.tpl
@@ -22,7 +22,7 @@
         element = document.Main.elements[i];
         if ( element.type == 'radio' && element.name === mainPriceFieldName ) {
           if (element.value == '0' ) {
-            element.click();
+            element.checked = true;
           }
           else {
             element.checked = false;
diff --git a/civicrm/templates/CRM/Price/Page/LineItem.tpl b/civicrm/templates/CRM/Price/Page/LineItem.tpl
index 8635cf90288d0938c4f92f5f056068f5e59b4e94..e7144912112b144ba86f4822d83bc2f2580cf4ad 100644
--- a/civicrm/templates/CRM/Price/Page/LineItem.tpl
+++ b/civicrm/templates/CRM/Price/Page/LineItem.tpl
@@ -72,7 +72,7 @@
         <td></td>
         <td></td>
       {/if}
-      <td class="right">{$line.line_total+$line.tax_amount|crmMoney:$currency}</td>
+      <td class="right">{assign var=totalWithTax value=$line.line_total+$line.tax_amount}{$totalWithTax|crmMoney:$currency}</td>
     {/if}
           {if $pricesetFieldsCount}
             <td class="right">{$line.participant_count}</td>
@@ -92,7 +92,8 @@
       {ts}Contribution Total{/ts}:
     {elseif $context EQ "Event"}
       {if $totalTaxAmount}
-        {ts}Event SubTotal: {$totalAmount-$totalTaxAmount|crmMoney:$currency}{/ts}<br />
+        {assign var=eventSubTotal value=$totalAmount-$totalTaxAmount}
+        {ts 1=$eventSubTotal|crmMoney:$currency}Event SubTotal: %1{/ts}<br />
       {/if}
       {ts}Total Amount{/ts}:
     {elseif $context EQ "Membership"}
diff --git a/civicrm/vendor/autoload.php b/civicrm/vendor/autoload.php
index 7d254f595fe08ab1f7fc8a2d3e314d152e498098..4d99ded32f55c1e2a6ccef146f48b5d57d6e542b 100644
--- a/civicrm/vendor/autoload.php
+++ b/civicrm/vendor/autoload.php
@@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
 
 require_once __DIR__ . '/composer/autoload_real.php';
 
-return ComposerAutoloaderInit0fcbe1ec640ae9fe693b02538241f085::getLoader();
+return ComposerAutoloaderInite36d44b412c906747bbbe03020d7d072::getLoader();
diff --git a/civicrm/vendor/composer/autoload_real.php b/civicrm/vendor/composer/autoload_real.php
index 9109da896636f5ea1516f649edae2fdf4f964a61..9ba5ef25b59ca049337e1463ad199af3ef4129ef 100644
--- a/civicrm/vendor/composer/autoload_real.php
+++ b/civicrm/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInit0fcbe1ec640ae9fe693b02538241f085
+class ComposerAutoloaderInite36d44b412c906747bbbe03020d7d072
 {
     private static $loader;
 
@@ -24,22 +24,22 @@ class ComposerAutoloaderInit0fcbe1ec640ae9fe693b02538241f085
 
         require __DIR__ . '/platform_check.php';
 
-        spl_autoload_register(array('ComposerAutoloaderInit0fcbe1ec640ae9fe693b02538241f085', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInite36d44b412c906747bbbe03020d7d072', 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
-        spl_autoload_unregister(array('ComposerAutoloaderInit0fcbe1ec640ae9fe693b02538241f085', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInite36d44b412c906747bbbe03020d7d072', 'loadClassLoader'));
 
         $includePaths = require __DIR__ . '/include_paths.php';
         $includePaths[] = get_include_path();
         set_include_path(implode(PATH_SEPARATOR, $includePaths));
 
         require __DIR__ . '/autoload_static.php';
-        call_user_func(\Composer\Autoload\ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085::getInitializer($loader));
+        call_user_func(\Composer\Autoload\ComposerStaticInite36d44b412c906747bbbe03020d7d072::getInitializer($loader));
 
         $loader->register(true);
 
-        $includeFiles = \Composer\Autoload\ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085::$files;
+        $includeFiles = \Composer\Autoload\ComposerStaticInite36d44b412c906747bbbe03020d7d072::$files;
         foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire0fcbe1ec640ae9fe693b02538241f085($fileIdentifier, $file);
+            composerRequiree36d44b412c906747bbbe03020d7d072($fileIdentifier, $file);
         }
 
         return $loader;
@@ -51,7 +51,7 @@ class ComposerAutoloaderInit0fcbe1ec640ae9fe693b02538241f085
  * @param string $file
  * @return void
  */
-function composerRequire0fcbe1ec640ae9fe693b02538241f085($fileIdentifier, $file)
+function composerRequiree36d44b412c906747bbbe03020d7d072($fileIdentifier, $file)
 {
     if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
         $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
diff --git a/civicrm/vendor/composer/autoload_static.php b/civicrm/vendor/composer/autoload_static.php
index 6c7aa78c9fcfd983bf37f9abf8b60da9c184e902..e75a9e1d8e293bdc654ce55810ca464a80aeaf5f 100644
--- a/civicrm/vendor/composer/autoload_static.php
+++ b/civicrm/vendor/composer/autoload_static.php
@@ -4,7 +4,7 @@
 
 namespace Composer\Autoload;
 
-class ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085
+class ComposerStaticInite36d44b412c906747bbbe03020d7d072
 {
     public static $files = array (
         'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
@@ -713,11 +713,11 @@ class ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085::$prefixDirsPsr4;
-            $loader->prefixesPsr0 = ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085::$prefixesPsr0;
-            $loader->fallbackDirsPsr0 = ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085::$fallbackDirsPsr0;
-            $loader->classMap = ComposerStaticInit0fcbe1ec640ae9fe693b02538241f085::$classMap;
+            $loader->prefixLengthsPsr4 = ComposerStaticInite36d44b412c906747bbbe03020d7d072::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInite36d44b412c906747bbbe03020d7d072::$prefixDirsPsr4;
+            $loader->prefixesPsr0 = ComposerStaticInite36d44b412c906747bbbe03020d7d072::$prefixesPsr0;
+            $loader->fallbackDirsPsr0 = ComposerStaticInite36d44b412c906747bbbe03020d7d072::$fallbackDirsPsr0;
+            $loader->classMap = ComposerStaticInite36d44b412c906747bbbe03020d7d072::$classMap;
 
         }, null, ClassLoader::class);
     }
diff --git a/civicrm/vendor/composer/installed.php b/civicrm/vendor/composer/installed.php
index b25cdac267614eb25e1a673b664851cd4db6c091..52232eb15b982368a8f5edc8dc3b15521bc029a1 100644
--- a/civicrm/vendor/composer/installed.php
+++ b/civicrm/vendor/composer/installed.php
@@ -3,7 +3,7 @@
         'name' => 'civicrm/civicrm-core',
         'pretty_version' => '5.69.x-dev',
         'version' => '5.69.9999999.9999999-dev',
-        'reference' => 'b74e1246ea7d980ff89773c5f22186b95fc4d3bb',
+        'reference' => 'c3f742eff3a4248f26ed499e5ea61b2deee461e9',
         'type' => 'library',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -40,7 +40,7 @@
         'civicrm/civicrm-core' => array(
             'pretty_version' => '5.69.x-dev',
             'version' => '5.69.9999999.9999999-dev',
-            'reference' => 'b74e1246ea7d980ff89773c5f22186b95fc4d3bb',
+            'reference' => 'c3f742eff3a4248f26ed499e5ea61b2deee461e9',
             'type' => 'library',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
diff --git a/civicrm/xml/version.xml b/civicrm/xml/version.xml
index e0fb9ccfbce0b39a50e5ae116915d64d56522b8e..36efda8d5e96b1b306b18596cf7b037d5bcf7eb7 100644
--- a/civicrm/xml/version.xml
+++ b/civicrm/xml/version.xml
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="iso-8859-1" ?>
 <version>
-  <version_no>5.69.2</version_no>
+  <version_no>5.69.3</version_no>
 </version>