| @@ -814,9 +814,9 @@ | ||
| 814 | 814 | } |
| 815 | 815 | |
| 816 | 816 | $label_parts = explode( '-lbl-', $field_name ); |
| 817 | 817 | $label = isset( $label_parts[1] ) ? explode( '-', $label_parts[1] )[0] : ''; |
| 818 | - $label = $label ? Helper::decrypt( $label ) : ''; | |
| 818 | + $label = $label ? Helper::decode( $label ) : ''; | |
| 819 | 819 | $field_block_name = Helper::get_block_name_from_field( $field_name ); |
| 820 | 820 | |
| 821 | 821 | /** |
| 822 | 822 | * Filter: 'srfm_entry_value' |
| @@ -822,9 +822,11 @@ | ||
| 822 | 822 | * Filter: 'srfm_entry_value' |
| 823 | 823 | * |
| 824 | 824 | * This filter is used to allow 3rd party plugins or custom code to modify |
| 825 | 825 | * the entry field value in the entry details REST API response, if required. |
| 826 | - * For example, you may want to decrypt, format, or mask sensitive data before output. | |
| 826 | + * For example, you may want to format, mask, or otherwise transform sensitive | |
| 827 | + * data before output. Note the value reaching this filter is not encrypted by | |
| 828 | + * SureForms — labels and values are carried as unkeyed base64 at most. | |
| 827 | 829 | * |
| 828 | 830 | * @since 2.0.0 |
| 829 | 831 | * |
| 830 | 832 | * @param mixed $value The original value for the field. |
| @@ -1238,9 +1240,9 @@ | ||
| 1238 | 1240 | $field_name = ''; |
| 1239 | 1241 | $base_field_name = ''; |
| 1240 | 1242 | |
| 1241 | 1243 | if ( ! empty( $label ) && ! empty( $slug ) && ! empty( $block_id ) ) { |
| 1242 | - $input_label = '-lbl-' . Helper::encrypt( $label ); | |
| 1244 | + $input_label = '-lbl-' . Helper::encode( $label ); | |
| 1243 | 1245 | $base_field_name = $input_label . '-' . $slug; |
| 1244 | 1246 | |
| 1245 | 1247 | // Handle special case for dropdown with instance counter. |
| 1246 | 1248 | if ( 'dropdown' === $block_type ) { |
| @@ -1394,9 +1396,9 @@ | ||
| 1394 | 1396 | */ |
| 1395 | 1397 | return apply_filters( |
| 1396 | 1398 | 'srfm_rest_api_endpoints', |
| 1397 | 1399 | [ |
| 1398 | - 'generate-form' => [ | |
| 1400 | + 'generate-form' => [ | |
| 1399 | 1401 | 'methods' => 'POST', |
| 1400 | 1402 | 'callback' => [ AI_Form_Builder::get_instance(), 'generate_ai_form' ], |
| 1401 | 1403 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1402 | 1404 | 'args' => [ |
| @@ -1405,21 +1407,100 @@ | ||
| 1405 | 1407 | ], |
| 1406 | 1408 | ], |
| 1407 | 1409 | ], |
| 1408 | 1410 | // This route is used to map the AI response to SureForms fields markup. |
| 1409 | - 'map-fields' => [ | |
| 1411 | + 'map-fields' => [ | |
| 1410 | 1412 | 'methods' => 'POST', |
| 1411 | 1413 | 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], |
| 1412 | 1414 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1413 | 1415 | ], |
| 1416 | + // Recreate the entries table when it has gone missing. The repair is | |
| 1417 | + // idempotent (CREATE TABLE IF NOT EXISTS) so a double-click is safe. | |
| 1418 | + 'database/repair-entries-table' => [ | |
| 1419 | + 'methods' => 'POST', | |
| 1420 | + /** | |
| 1421 | + * Resolved at dispatch, not while the route table is built: | |
| 1422 | + * get_endpoints() runs on rest_api_init for every REST request, | |
| 1423 | + * and Admin is only constructed under is_admin(). Naming the | |
| 1424 | + * instance here would run Admin's constructor on the front-end | |
| 1425 | + * submit path too. | |
| 1426 | + * | |
| 1427 | + * @param \WP_REST_Request<array<string,mixed>> $request Request. | |
| 1428 | + * @return \WP_REST_Response|\WP_Error | |
| 1429 | + */ | |
| 1430 | + 'callback' => static function ( $request ) { | |
| 1431 | + $nonce = Helper::get_string_value( $request->get_header( 'X-WP-Nonce' ) ); | |
| 1432 | + | |
| 1433 | + if ( ! wp_verify_nonce( sanitize_text_field( $nonce ), 'wp_rest' ) ) { | |
| 1434 | + return new \WP_Error( | |
| 1435 | + 'rest_cookie_invalid_nonce', | |
| 1436 | + __( 'Security verification failed. Please refresh the page and try again.', 'sureforms' ), | |
| 1437 | + [ 'status' => 403 ] | |
| 1438 | + ); | |
| 1439 | + } | |
| 1440 | + | |
| 1441 | + // @phpstan-ignore-next-line -- PHPStan resolves SRFM\Admin\Admin via tests/php/stubs/srfm-stubs.php (admin/ is outside its `paths`) and that generated stub predates this method. Real location: admin/admin.php. | |
| 1442 | + $repaired = \SRFM\Admin\Admin::get_instance()->do_database_repair(); | |
| 1443 | + | |
| 1444 | + if ( ! $repaired ) { | |
| 1445 | + return new \WP_Error( | |
| 1446 | + 'srfm_database_repair_failed', | |
| 1447 | + __( 'SureForms could not finish updating the database. Your hosting may not allow SureForms to create database tables — please contact your hosting provider or SureForms support.', 'sureforms' ), | |
| 1448 | + [ 'status' => 500 ] | |
| 1449 | + ); | |
| 1450 | + } | |
| 1451 | + | |
| 1452 | + return new \WP_REST_Response( [ 'success' => true ], 200 ); | |
| 1453 | + }, | |
| 1454 | + 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], | |
| 1455 | + ], | |
| 1456 | + // Record a "Finish setting up" card CTA click for a form (#3031). | |
| 1457 | + // Per-form capability is re-checked in the handler. | |
| 1458 | + 'dismiss-form-setup-card' => [ | |
| 1459 | + 'methods' => 'POST', | |
| 1460 | + /** | |
| 1461 | + * Resolve Admin at dispatch rather than while the route table is | |
| 1462 | + * built. get_endpoints() runs on rest_api_init for *every* REST | |
| 1463 | + * request, and plugin-loader.php only constructs Admin under | |
| 1464 | + * is_admin() — which REST dispatch is not. Naming the instance | |
| 1465 | + * here would therefore run Admin's constructor (40 admin hook | |
| 1466 | + * registrations, an option read, the notices library, and the | |
| 1467 | + * wpforms_current_user_can filter) on the front-end | |
| 1468 | + * submit-form path too. | |
| 1469 | + * | |
| 1470 | + * @param \WP_REST_Request<array<string,mixed>> $request Request. | |
| 1471 | + * @return \WP_REST_Response|\WP_Error | |
| 1472 | + */ | |
| 1473 | + 'callback' => static function ( $request ) { | |
| 1474 | + // @phpstan-ignore-next-line -- PHPStan resolves SRFM\Admin\Admin via tests/php/stubs/srfm-stubs.php (admin/ is outside its `paths`) and that generated stub predates this method. Real location: admin/admin.php:470. | |
| 1475 | + return \SRFM\Admin\Admin::get_instance()->dismiss_form_setup_card( $request ); | |
| 1476 | + }, | |
| 1477 | + 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], | |
| 1478 | + 'args' => [ | |
| 1479 | + 'form_id' => [ | |
| 1480 | + 'required' => true, | |
| 1481 | + 'sanitize_callback' => 'absint', | |
| 1482 | + ], | |
| 1483 | + 'action' => [ | |
| 1484 | + 'required' => true, | |
| 1485 | + 'type' => 'string', | |
| 1486 | + 'enum' => [ 'edit_form', 'edit_thankyou', 'set_up_email', 'view_form' ], | |
| 1487 | + // Core only enforces `enum` via the default arg sanitizer, which | |
| 1488 | + // is skipped once a sanitize_callback is set — so pair it with an | |
| 1489 | + // explicit validate_callback, matching this file's other routes. | |
| 1490 | + 'validate_callback' => 'rest_validate_request_arg', | |
| 1491 | + 'sanitize_callback' => 'sanitize_text_field', | |
| 1492 | + ], | |
| 1493 | + ], | |
| 1494 | + ], | |
| 1414 | 1495 | // This route is used to initiate auth process when user tries to authenticate on billing portal. |
| 1415 | - 'initiate-auth' => [ | |
| 1496 | + 'initiate-auth' => [ | |
| 1416 | 1497 | 'methods' => 'GET', |
| 1417 | 1498 | 'callback' => [ AI_Auth::get_instance(), 'get_auth_url' ], |
| 1418 | 1499 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1419 | 1500 | ], |
| 1420 | 1501 | // This route is to used to decrypt the access key and save it in the database. |
| 1421 | - 'handle-access-key' => [ | |
| 1502 | + 'handle-access-key' => [ | |
| 1422 | 1503 | 'methods' => 'POST', |
| 1423 | 1504 | 'callback' => [ AI_Auth::get_instance(), 'handle_access_key' ], |
| 1424 | 1505 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1425 | 1506 | ], |
| @@ -1425,27 +1506,27 @@ | ||
| 1425 | 1506 | ], |
| 1426 | 1507 | // Public route: returns the visitor's detected country code. Called |
| 1427 | 1508 | // per-visitor from the phone field so auto-country detection works |
| 1428 | 1509 | // on full-page-cached sites (the value isn't baked into cached HTML). |
| 1429 | - 'geo-country' => [ | |
| 1510 | + 'geo-country' => [ | |
| 1430 | 1511 | 'methods' => 'GET', |
| 1431 | 1512 | 'callback' => [ $this, 'get_geo_country' ], |
| 1432 | 1513 | 'permission_callback' => '__return_true', |
| 1433 | 1514 | ], |
| 1434 | 1515 | // This route is to get the form submissions for the last 30 days. |
| 1435 | - 'entries-chart-data' => [ | |
| 1516 | + 'entries-chart-data' => [ | |
| 1436 | 1517 | 'methods' => 'GET', |
| 1437 | 1518 | 'callback' => [ $this, 'get_entries_chart_data' ], |
| 1438 | 1519 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1439 | 1520 | ], |
| 1440 | 1521 | // This route is to get all forms data. |
| 1441 | - 'form-data' => [ | |
| 1522 | + 'form-data' => [ | |
| 1442 | 1523 | 'methods' => 'GET', |
| 1443 | 1524 | 'callback' => [ $this, 'get_form_data' ], |
| 1444 | 1525 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1445 | 1526 | ], |
| 1446 | 1527 | // Page search endpoint for async admin dropdowns. |
| 1447 | - 'pages/search' => [ | |
| 1528 | + 'pages/search' => [ | |
| 1448 | 1529 | 'methods' => 'GET', |
| 1449 | 1530 | 'callback' => [ $this, 'search_pages' ], |
| 1450 | 1531 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1451 | 1532 | 'args' => [ |
| @@ -1495,19 +1576,19 @@ | ||
| 1495 | 1576 | ], |
| 1496 | 1577 | ], |
| 1497 | 1578 | ], |
| 1498 | 1579 | // Onboarding endpoints. |
| 1499 | - 'onboarding/set-status' => [ | |
| 1580 | + 'onboarding/set-status' => [ | |
| 1500 | 1581 | 'methods' => 'POST', |
| 1501 | 1582 | 'callback' => [ $this, 'set_onboarding_status' ], |
| 1502 | 1583 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1503 | 1584 | ], |
| 1504 | - 'onboarding/get-status' => [ | |
| 1585 | + 'onboarding/get-status' => [ | |
| 1505 | 1586 | 'methods' => 'GET', |
| 1506 | 1587 | 'callback' => [ $this, 'get_onboarding_status' ], |
| 1507 | 1588 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1508 | 1589 | ], |
| 1509 | - 'onboarding/user-details' => [ | |
| 1590 | + 'onboarding/user-details' => [ | |
| 1510 | 1591 | 'methods' => 'POST', |
| 1511 | 1592 | 'callback' => [ $this, 'save_onboarding_user_details' ], |
| 1512 | 1593 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1513 | 1594 | 'args' => [ |
| @@ -1531,9 +1612,9 @@ | ||
| 1531 | 1612 | ], |
| 1532 | 1613 | ], |
| 1533 | 1614 | ], |
| 1534 | 1615 | // Plugin status endpoint. |
| 1535 | - 'plugin-status' => [ | |
| 1616 | + 'plugin-status' => [ | |
| 1536 | 1617 | 'methods' => 'GET', |
| 1537 | 1618 | 'callback' => [ $this, 'get_plugin_status' ], |
| 1538 | 1619 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1539 | 1620 | 'args' => [ |
| @@ -1543,9 +1624,9 @@ | ||
| 1543 | 1624 | ], |
| 1544 | 1625 | ], |
| 1545 | 1626 | ], |
| 1546 | 1627 | // Entries endpoints. |
| 1547 | - 'entries/list' => [ | |
| 1628 | + 'entries/list' => [ | |
| 1548 | 1629 | 'methods' => 'GET', |
| 1549 | 1630 | 'callback' => [ $this, 'get_entries_list' ], |
| 1550 | 1631 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1551 | 1632 | 'args' => [ |
| @@ -1590,9 +1671,9 @@ | ||
| 1590 | 1671 | 'default' => 1, |
| 1591 | 1672 | ], |
| 1592 | 1673 | ], |
| 1593 | 1674 | ], |
| 1594 | - 'entries/read-status' => [ | |
| 1675 | + 'entries/read-status' => [ | |
| 1595 | 1676 | 'methods' => 'POST', |
| 1596 | 1677 | 'callback' => [ $this, 'update_entries_read_status' ], |
| 1597 | 1678 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1598 | 1679 | 'args' => [ |
| @@ -1606,9 +1687,9 @@ | ||
| 1606 | 1687 | 'validate_callback' => [ $this, 'validate_read_action' ], |
| 1607 | 1688 | ], |
| 1608 | 1689 | ], |
| 1609 | 1690 | ], |
| 1610 | - 'entries/trash' => [ | |
| 1691 | + 'entries/trash' => [ | |
| 1611 | 1692 | 'methods' => 'POST', |
| 1612 | 1693 | 'callback' => [ $this, 'update_entries_trash_status' ], |
| 1613 | 1694 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1614 | 1695 | 'args' => [ |
| @@ -1622,9 +1703,9 @@ | ||
| 1622 | 1703 | 'validate_callback' => [ $this, 'validate_trash_action' ], |
| 1623 | 1704 | ], |
| 1624 | 1705 | ], |
| 1625 | 1706 | ], |
| 1626 | - 'entries/delete' => [ | |
| 1707 | + 'entries/delete' => [ | |
| 1627 | 1708 | 'methods' => 'POST', |
| 1628 | 1709 | 'callback' => [ $this, 'delete_entries' ], |
| 1629 | 1710 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1630 | 1711 | 'args' => [ |
| @@ -1633,9 +1714,9 @@ | ||
| 1633 | 1714 | 'sanitize_callback' => [ $this, 'sanitize_entry_ids' ], |
| 1634 | 1715 | ], |
| 1635 | 1716 | ], |
| 1636 | 1717 | ], |
| 1637 | - 'entries/export' => [ | |
| 1718 | + 'entries/export' => [ | |
| 1638 | 1719 | 'methods' => 'POST', |
| 1639 | 1720 | 'callback' => [ $this, 'export_entries' ], |
| 1640 | 1721 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1641 | 1722 | 'args' => [ |
| @@ -1665,9 +1746,9 @@ | ||
| 1665 | 1746 | ], |
| 1666 | 1747 | ], |
| 1667 | 1748 | ], |
| 1668 | 1749 | // Get Single Entry Form Data. |
| 1669 | - 'entry/(?P<id>\d+)/details' => [ | |
| 1750 | + 'entry/(?P<id>\d+)/details' => [ | |
| 1670 | 1751 | 'methods' => 'GET', |
| 1671 | 1752 | 'callback' => [ $this, 'get_entry_details' ], |
| 1672 | 1753 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1673 | 1754 | 'args' => [ |
| @@ -1677,9 +1758,9 @@ | ||
| 1677 | 1758 | ], |
| 1678 | 1759 | ], |
| 1679 | 1760 | ], |
| 1680 | 1761 | // Get Single Entry Logs. |
| 1681 | - 'entry/(?P<id>\d+)/logs' => [ | |
| 1762 | + 'entry/(?P<id>\d+)/logs' => [ | |
| 1682 | 1763 | 'methods' => 'GET', |
| 1683 | 1764 | 'callback' => [ $this, 'get_entry_logs' ], |
| 1684 | 1765 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1685 | 1766 | 'args' => [ |
| @@ -1697,9 +1778,9 @@ | ||
| 1697 | 1778 | ], |
| 1698 | 1779 | ], |
| 1699 | 1780 | ], |
| 1700 | 1781 | // Forms listing endpoint. |
| 1701 | - 'forms' => [ | |
| 1782 | + 'forms' => [ | |
| 1702 | 1783 | 'methods' => 'GET', |
| 1703 | 1784 | 'callback' => [ Forms_Data::get_instance(), 'get_forms_list' ], |
| 1704 | 1785 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1705 | 1786 | 'args' => [ |
| @@ -1723,9 +1804,9 @@ | ||
| 1723 | 1804 | ], |
| 1724 | 1805 | 'orderby' => [ |
| 1725 | 1806 | 'type' => 'string', |
| 1726 | 1807 | 'default' => 'date', |
| 1727 | - 'enum' => [ 'date', 'id', 'title', 'modified' ], | |
| 1808 | + 'enum' => [ 'date', 'id', 'title', 'modified', 'views', 'conversion_rate' ], | |
| 1728 | 1809 | ], |
| 1729 | 1810 | 'order' => [ |
| 1730 | 1811 | 'type' => 'string', |
| 1731 | 1812 | 'default' => 'desc', |
| @@ -1755,9 +1836,9 @@ | ||
| 1755 | 1836 | ], |
| 1756 | 1837 | ], |
| 1757 | 1838 | ], |
| 1758 | 1839 | // Export forms endpoint. |
| 1759 | - 'forms/export' => [ | |
| 1840 | + 'forms/export' => [ | |
| 1760 | 1841 | 'methods' => 'POST', |
| 1761 | 1842 | 'callback' => [ Export::get_instance(), 'handle_export_form_rest' ], |
| 1762 | 1843 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1763 | 1844 | 'args' => [ |
| @@ -1779,9 +1860,9 @@ | ||
| 1779 | 1860 | ], |
| 1780 | 1861 | ], |
| 1781 | 1862 | ], |
| 1782 | 1863 | // Import forms endpoint. |
| 1783 | - 'forms/import' => [ | |
| 1864 | + 'forms/import' => [ | |
| 1784 | 1865 | 'methods' => 'POST', |
| 1785 | 1866 | 'callback' => [ Export::get_instance(), 'handle_import_form_rest' ], |
| 1786 | 1867 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1787 | 1868 | 'args' => [ |
| @@ -1801,9 +1882,9 @@ | ||
| 1801 | 1882 | ], |
| 1802 | 1883 | ], |
| 1803 | 1884 | ], |
| 1804 | 1885 | // Form lifecycle management endpoint (trash/restore/delete/draft). |
| 1805 | - 'forms/manage' => [ | |
| 1886 | + 'forms/manage' => [ | |
| 1806 | 1887 | 'methods' => 'POST', |
| 1807 | 1888 | 'callback' => [ $this, 'manage_form_lifecycle' ], |
| 1808 | 1889 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1809 | 1890 | 'args' => [ |
| @@ -1831,9 +1912,9 @@ | ||
| 1831 | 1912 | ], |
| 1832 | 1913 | ], |
| 1833 | 1914 | ], |
| 1834 | 1915 | // Form duplication endpoint. |
| 1835 | - 'forms/duplicate' => [ | |
| 1916 | + 'forms/duplicate' => [ | |
| 1836 | 1917 | 'methods' => 'POST', |
| 1837 | 1918 | 'callback' => [ Duplicate_Form::get_instance(), 'handle_duplicate_form_rest' ], |
| 1838 | 1919 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1839 | 1920 | 'args' => [ |