PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.10.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.10.0
5.12.0 5.13.0 5.13.1 5.11.0 5.10.0 5.9.0 5.8.0 5.8.1 5.7.0 5.6.2 5.6.3 5.6.1 5.6.0 5.5.0 5.4.0 5.3.2 5.3.1 5.1.6 5.1.5 trunk 2.1.5 2.11 2.12 2.13 2.15 All 47 releases
← All changes | src/Admin/AdminRestController.php +0 -128 5.12.0 → 5.10.0 View file →
@@ -17,9 +17,8 @@
17 17 use Forge12\DoubleOptIn\FormSettings\FormSettingsValidator;
18 18 use Forge12\DoubleOptIn\Integration\SubmittedContent;
19 19 use Forge12\DoubleOptIn\Service\ConfirmationMailResender;
20 20 use Forge12\DoubleOptIn\Service\ResendResult;
21 -use Forge12\DoubleOptIn\Subscription\SubscriptionGroups;
22 21 use Forge12\Shared\LoggerInterface;
23 22
24 23 if ( ! defined( 'ABSPATH' ) ) {
25 24 exit;
@@ -114,19 +113,8 @@
114 113 'permission_callback' => array( $this, 'checkPermission' ),
115 114 )
116 115 );
117 116
118 - // ── Subscription groups (read-only; managed by an add-on) ──
119 - register_rest_route(
120 - self::API_NAMESPACE,
121 - '/subscription-groups',
122 - array(
123 - 'methods' => \WP_REST_Server::READABLE,
124 - 'callback' => array( $this, 'getSubscriptionGroups' ),
125 - 'permission_callback' => array( $this, 'checkPermission' ),
126 - )
127 - );
128 -
129 117 // ── Opt-Ins ────────────────────────────────────────────────
130 118 register_rest_route(
131 119 self::API_NAMESPACE,
132 120 '/optins',
@@ -715,35 +703,8 @@
715 703 // ═══════════════════════════════════════════════════════════════
716 704 // OPT-INS
717 705 // ═══════════════════════════════════════════════════════════════
718 706
719 - /**
720 - * Subscription groups for the filter in the opt-in list. `available`
721 - * is false when no add-on provides groups, so the SPA hides the
722 - * controls instead of showing an empty filter.
723 - */
724 - public function getSubscriptionGroups( \WP_REST_Request $request ): \WP_REST_Response {
725 - $groups = array();
726 - foreach ( SubscriptionGroups::resolver()->groups() as $group ) {
727 - $groups[] = array(
728 - 'key' => $group->getKey(),
729 - 'label' => $group->getLabel(),
730 - 'memberCount' => count( $group->getMembers() ),
731 - );
732 - }
733 -
734 - return new \WP_REST_Response(
735 - array(
736 - 'success' => true,
737 - 'data' => array(
738 - 'available' => SubscriptionGroups::isAvailable(),
739 - 'groups' => $groups,
740 - ),
741 - ),
742 - 200
743 - );
744 - }
745 -
746 707 public function getOptins( \WP_REST_Request $request ): \WP_REST_Response {
747 708 $page = max( 1, (int) $request->get_param( 'page' ) ?: 1 );
748 709 $perPage = max( 1, min( 100, (int) $request->get_param( 'per_page' ) ?: 20 ) );
749 710 $search = sanitize_text_field( $request->get_param( 'search' ) ?? '' );
@@ -781,22 +742,8 @@
781 742 $where[] = 'cf_form_id = %d';
782 743 $params[] = (int) $formId;
783 744 }
784 745
785 - // Subscription group (5.12.0). An unknown key selects nothing, so a
786 - // stale link can never widen into the unfiltered list.
787 - $groupKey = sanitize_text_field( (string) ( $request->get_param( 'group' ) ?? '' ) );
788 - if ( $groupKey !== '' ) {
789 - $group = SubscriptionGroups::resolver()->findGroup( $groupKey );
790 - if ( $group === null ) {
791 - $where[] = '1 = 0';
792 - } else {
793 - list( $groupSql, $groupParams ) = $group->toSqlCondition();
794 - $where[] = $groupSql;
795 - $params = array_merge( $params, $groupParams );
796 - }
797 - }
798 -
799 746 // Opt-ins whose confirmation mail could not be sent (5.8.0).
800 747 if ( sanitize_text_field( (string) ( $request->get_param( 'mail' ) ?? '' ) ) === 'failed' ) {
801 748 $where[] = 'mail_status = %s';
802 749 $params[] = \Forge12\DoubleOptIn\Repository\OptInMailStatusRepository::FAILED;
@@ -865,12 +812,8 @@
865 812 }
866 813
867 814 $data = $this->formatOptinRow( $row, true );
868 815
869 - // Other sign-ups of the same address in the same subscription
870 - // group (5.12.0). The records stay separate; this only links them.
871 - $data['linkedOptIns'] = $this->linkedOptIns( $row );
872 -
873 816 // Dev-mode UI hint: surface whether the reset-confirmation
874 817 // endpoint is reachable for this request, so the React detail
875 818 // page can show/hide the "Reset to pending" button without
876 819 // having to probe the endpoint and handle a 403. Mirrors
@@ -2261,74 +2204,8 @@
2261 2204 * @param bool $detailed Whether to include full detail (content, mail data).
2262 2205 *
2263 2206 * @return array Formatted data.
2264 2207 */
2265 - /**
2266 - * @param array<string, mixed> $row A database row.
2267 - *
2268 - * @return array{key:string, label:string}|null
2269 - */
2270 - private function subscriptionOfRow( array $row ): ?array {
2271 - $group = SubscriptionGroups::resolver()->groupForForm(
2272 - (int) ( $row['cf_form_id'] ?? 0 ),
2273 - (string) ( $row['form_ref'] ?? '' )
2274 - );
2275 -
2276 - return $group === null ? null : array(
2277 - 'key' => $group->getKey(),
2278 - 'label' => $group->getLabel(),
2279 - );
2280 - }
2281 -
2282 - /**
2283 - * The other records of the same address that belong to the same
2284 - * subscription group as the given record.
2285 - *
2286 - * @param array<string, mixed> $row A database row.
2287 - *
2288 - * @return array<int, array<string, mixed>>
2289 - */
2290 - private function linkedOptIns( array $row ): array {
2291 - $group = SubscriptionGroups::resolver()->groupForForm(
2292 - (int) ( $row['cf_form_id'] ?? 0 ),
2293 - (string) ( $row['form_ref'] ?? '' )
2294 - );
2295 - $email = (string) ( $row['email'] ?? '' );
2296 - if ( $group === null || $email === '' ) {
2297 - return array();
2298 - }
2299 -
2300 - global $wpdb;
2301 - $table = $wpdb->prefix . 'f12_cf7_doubleoptin';
2302 - list( $groupSql, $groupParams ) = $group->toSqlCondition();
2303 -
2304 - // The group condition is built from fixed column names and `%d`/`%s`
2305 - // placeholders only; every value travels in the parameter list.
2306 - $found = $wpdb->get_results(
2307 - $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- placeholders come from SubscriptionGroup::toSqlCondition().
2308 - "SELECT * FROM {$table} WHERE email = %s AND id <> %d AND {$groupSql} ORDER BY id DESC LIMIT 50", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
2309 - array_merge( array( $email, (int) $row['id'] ), $groupParams )
2310 - ),
2311 - ARRAY_A
2312 - );
2313 -
2314 - $linked = array();
2315 - foreach ( (array) $found as $other ) {
2316 - $data = $this->formatOptinRow( $other );
2317 - $linked[] = array(
2318 - 'id' => $data['id'],
2319 - 'formId' => $data['formId'],
2320 - 'formName' => $data['formName'],
2321 - 'formRef' => $data['formRef'],
2322 - 'confirmed' => $data['confirmed'],
2323 - 'revoked' => $data['revoked'],
2324 - 'createtime' => $data['createtime'],
2325 - );
2326 - }
2327 -
2328 - return $linked;
2329 - }
2330 -
2331 2208 private function formatOptinRow( array $row, bool $detailed = false ): array {
2332 2209 $post = get_post( (int) $row['cf_form_id'] );
2333 2210
2334 2211 $data = array(
@@ -2346,13 +2223,8 @@
2346 2223 'mailStatus' => (string) ( $row['mail_status'] ?? '' ),
2347 2224 'createtime' => $this->toSiteLocalTime( $row['createtime'] ),
2348 2225 'updatetime' => $this->toSiteLocalTime( $row['updatetime'] ),
2349 2226 );
2350 -
2351 - // Instance inside the form id, e.g. the Elementor widget (5.12.0).
2352 - $data['formRef'] = (string) ( $row['form_ref'] ?? '' );
2353 - // Subscription group of the record, or null (5.12.0).
2354 - $data['subscription'] = $this->subscriptionOfRow( $row );
2355 2227
2356 2228 if ( $detailed ) {
2357 2229 $data['ipRegister'] = $row['ipaddr_register'];
2358 2230 $data['ipConfirmation'] = $row['ipaddr_confirmation'];