| @@ -1396,9 +1396,9 @@ | ||
| 1396 | 1396 | */ |
| 1397 | 1397 | return apply_filters( |
| 1398 | 1398 | 'srfm_rest_api_endpoints', |
| 1399 | 1399 | [ |
| 1400 | - 'generate-form' => [ | |
| 1400 | + 'generate-form' => [ | |
| 1401 | 1401 | 'methods' => 'POST', |
| 1402 | 1402 | 'callback' => [ AI_Form_Builder::get_instance(), 'generate_ai_form' ], |
| 1403 | 1403 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1404 | 1404 | 'args' => [ |
| @@ -1407,16 +1407,56 @@ | ||
| 1407 | 1407 | ], |
| 1408 | 1408 | ], |
| 1409 | 1409 | ], |
| 1410 | 1410 | // This route is used to map the AI response to SureForms fields markup. |
| 1411 | - 'map-fields' => [ | |
| 1411 | + 'map-fields' => [ | |
| 1412 | 1412 | 'methods' => 'POST', |
| 1413 | 1413 | 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], |
| 1414 | 1414 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1415 | 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 | + ], | |
| 1416 | 1456 | // Record a "Finish setting up" card CTA click for a form (#3031). |
| 1417 | 1457 | // Per-form capability is re-checked in the handler. |
| 1418 | - 'dismiss-form-setup-card' => [ | |
| 1458 | + 'dismiss-form-setup-card' => [ | |
| 1419 | 1459 | 'methods' => 'POST', |
| 1420 | 1460 | /** |
| 1421 | 1461 | * Resolve Admin at dispatch rather than while the route table is |
| 1422 | 1462 | * built. get_endpoints() runs on rest_api_init for *every* REST |
| @@ -1452,15 +1492,15 @@ | ||
| 1452 | 1492 | ], |
| 1453 | 1493 | ], |
| 1454 | 1494 | ], |
| 1455 | 1495 | // This route is used to initiate auth process when user tries to authenticate on billing portal. |
| 1456 | - 'initiate-auth' => [ | |
| 1496 | + 'initiate-auth' => [ | |
| 1457 | 1497 | 'methods' => 'GET', |
| 1458 | 1498 | 'callback' => [ AI_Auth::get_instance(), 'get_auth_url' ], |
| 1459 | 1499 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1460 | 1500 | ], |
| 1461 | 1501 | // This route is to used to decrypt the access key and save it in the database. |
| 1462 | - 'handle-access-key' => [ | |
| 1502 | + 'handle-access-key' => [ | |
| 1463 | 1503 | 'methods' => 'POST', |
| 1464 | 1504 | 'callback' => [ AI_Auth::get_instance(), 'handle_access_key' ], |
| 1465 | 1505 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1466 | 1506 | ], |
| @@ -1466,27 +1506,27 @@ | ||
| 1466 | 1506 | ], |
| 1467 | 1507 | // Public route: returns the visitor's detected country code. Called |
| 1468 | 1508 | // per-visitor from the phone field so auto-country detection works |
| 1469 | 1509 | // on full-page-cached sites (the value isn't baked into cached HTML). |
| 1470 | - 'geo-country' => [ | |
| 1510 | + 'geo-country' => [ | |
| 1471 | 1511 | 'methods' => 'GET', |
| 1472 | 1512 | 'callback' => [ $this, 'get_geo_country' ], |
| 1473 | 1513 | 'permission_callback' => '__return_true', |
| 1474 | 1514 | ], |
| 1475 | 1515 | // This route is to get the form submissions for the last 30 days. |
| 1476 | - 'entries-chart-data' => [ | |
| 1516 | + 'entries-chart-data' => [ | |
| 1477 | 1517 | 'methods' => 'GET', |
| 1478 | 1518 | 'callback' => [ $this, 'get_entries_chart_data' ], |
| 1479 | 1519 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1480 | 1520 | ], |
| 1481 | 1521 | // This route is to get all forms data. |
| 1482 | - 'form-data' => [ | |
| 1522 | + 'form-data' => [ | |
| 1483 | 1523 | 'methods' => 'GET', |
| 1484 | 1524 | 'callback' => [ $this, 'get_form_data' ], |
| 1485 | 1525 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1486 | 1526 | ], |
| 1487 | 1527 | // Page search endpoint for async admin dropdowns. |
| 1488 | - 'pages/search' => [ | |
| 1528 | + 'pages/search' => [ | |
| 1489 | 1529 | 'methods' => 'GET', |
| 1490 | 1530 | 'callback' => [ $this, 'search_pages' ], |
| 1491 | 1531 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1492 | 1532 | 'args' => [ |
| @@ -1536,19 +1576,19 @@ | ||
| 1536 | 1576 | ], |
| 1537 | 1577 | ], |
| 1538 | 1578 | ], |
| 1539 | 1579 | // Onboarding endpoints. |
| 1540 | - 'onboarding/set-status' => [ | |
| 1580 | + 'onboarding/set-status' => [ | |
| 1541 | 1581 | 'methods' => 'POST', |
| 1542 | 1582 | 'callback' => [ $this, 'set_onboarding_status' ], |
| 1543 | 1583 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1544 | 1584 | ], |
| 1545 | - 'onboarding/get-status' => [ | |
| 1585 | + 'onboarding/get-status' => [ | |
| 1546 | 1586 | 'methods' => 'GET', |
| 1547 | 1587 | 'callback' => [ $this, 'get_onboarding_status' ], |
| 1548 | 1588 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1549 | 1589 | ], |
| 1550 | - 'onboarding/user-details' => [ | |
| 1590 | + 'onboarding/user-details' => [ | |
| 1551 | 1591 | 'methods' => 'POST', |
| 1552 | 1592 | 'callback' => [ $this, 'save_onboarding_user_details' ], |
| 1553 | 1593 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1554 | 1594 | 'args' => [ |
| @@ -1572,9 +1612,9 @@ | ||
| 1572 | 1612 | ], |
| 1573 | 1613 | ], |
| 1574 | 1614 | ], |
| 1575 | 1615 | // Plugin status endpoint. |
| 1576 | - 'plugin-status' => [ | |
| 1616 | + 'plugin-status' => [ | |
| 1577 | 1617 | 'methods' => 'GET', |
| 1578 | 1618 | 'callback' => [ $this, 'get_plugin_status' ], |
| 1579 | 1619 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1580 | 1620 | 'args' => [ |
| @@ -1584,9 +1624,9 @@ | ||
| 1584 | 1624 | ], |
| 1585 | 1625 | ], |
| 1586 | 1626 | ], |
| 1587 | 1627 | // Entries endpoints. |
| 1588 | - 'entries/list' => [ | |
| 1628 | + 'entries/list' => [ | |
| 1589 | 1629 | 'methods' => 'GET', |
| 1590 | 1630 | 'callback' => [ $this, 'get_entries_list' ], |
| 1591 | 1631 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1592 | 1632 | 'args' => [ |
| @@ -1631,9 +1671,9 @@ | ||
| 1631 | 1671 | 'default' => 1, |
| 1632 | 1672 | ], |
| 1633 | 1673 | ], |
| 1634 | 1674 | ], |
| 1635 | - 'entries/read-status' => [ | |
| 1675 | + 'entries/read-status' => [ | |
| 1636 | 1676 | 'methods' => 'POST', |
| 1637 | 1677 | 'callback' => [ $this, 'update_entries_read_status' ], |
| 1638 | 1678 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1639 | 1679 | 'args' => [ |
| @@ -1647,9 +1687,9 @@ | ||
| 1647 | 1687 | 'validate_callback' => [ $this, 'validate_read_action' ], |
| 1648 | 1688 | ], |
| 1649 | 1689 | ], |
| 1650 | 1690 | ], |
| 1651 | - 'entries/trash' => [ | |
| 1691 | + 'entries/trash' => [ | |
| 1652 | 1692 | 'methods' => 'POST', |
| 1653 | 1693 | 'callback' => [ $this, 'update_entries_trash_status' ], |
| 1654 | 1694 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1655 | 1695 | 'args' => [ |
| @@ -1663,9 +1703,9 @@ | ||
| 1663 | 1703 | 'validate_callback' => [ $this, 'validate_trash_action' ], |
| 1664 | 1704 | ], |
| 1665 | 1705 | ], |
| 1666 | 1706 | ], |
| 1667 | - 'entries/delete' => [ | |
| 1707 | + 'entries/delete' => [ | |
| 1668 | 1708 | 'methods' => 'POST', |
| 1669 | 1709 | 'callback' => [ $this, 'delete_entries' ], |
| 1670 | 1710 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1671 | 1711 | 'args' => [ |
| @@ -1674,9 +1714,9 @@ | ||
| 1674 | 1714 | 'sanitize_callback' => [ $this, 'sanitize_entry_ids' ], |
| 1675 | 1715 | ], |
| 1676 | 1716 | ], |
| 1677 | 1717 | ], |
| 1678 | - 'entries/export' => [ | |
| 1718 | + 'entries/export' => [ | |
| 1679 | 1719 | 'methods' => 'POST', |
| 1680 | 1720 | 'callback' => [ $this, 'export_entries' ], |
| 1681 | 1721 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1682 | 1722 | 'args' => [ |
| @@ -1706,9 +1746,9 @@ | ||
| 1706 | 1746 | ], |
| 1707 | 1747 | ], |
| 1708 | 1748 | ], |
| 1709 | 1749 | // Get Single Entry Form Data. |
| 1710 | - 'entry/(?P<id>\d+)/details' => [ | |
| 1750 | + 'entry/(?P<id>\d+)/details' => [ | |
| 1711 | 1751 | 'methods' => 'GET', |
| 1712 | 1752 | 'callback' => [ $this, 'get_entry_details' ], |
| 1713 | 1753 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1714 | 1754 | 'args' => [ |
| @@ -1718,9 +1758,9 @@ | ||
| 1718 | 1758 | ], |
| 1719 | 1759 | ], |
| 1720 | 1760 | ], |
| 1721 | 1761 | // Get Single Entry Logs. |
| 1722 | - 'entry/(?P<id>\d+)/logs' => [ | |
| 1762 | + 'entry/(?P<id>\d+)/logs' => [ | |
| 1723 | 1763 | 'methods' => 'GET', |
| 1724 | 1764 | 'callback' => [ $this, 'get_entry_logs' ], |
| 1725 | 1765 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1726 | 1766 | 'args' => [ |
| @@ -1738,9 +1778,9 @@ | ||
| 1738 | 1778 | ], |
| 1739 | 1779 | ], |
| 1740 | 1780 | ], |
| 1741 | 1781 | // Forms listing endpoint. |
| 1742 | - 'forms' => [ | |
| 1782 | + 'forms' => [ | |
| 1743 | 1783 | 'methods' => 'GET', |
| 1744 | 1784 | 'callback' => [ Forms_Data::get_instance(), 'get_forms_list' ], |
| 1745 | 1785 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1746 | 1786 | 'args' => [ |
| @@ -1764,9 +1804,9 @@ | ||
| 1764 | 1804 | ], |
| 1765 | 1805 | 'orderby' => [ |
| 1766 | 1806 | 'type' => 'string', |
| 1767 | 1807 | 'default' => 'date', |
| 1768 | - 'enum' => [ 'date', 'id', 'title', 'modified' ], | |
| 1808 | + 'enum' => [ 'date', 'id', 'title', 'modified', 'views', 'conversion_rate' ], | |
| 1769 | 1809 | ], |
| 1770 | 1810 | 'order' => [ |
| 1771 | 1811 | 'type' => 'string', |
| 1772 | 1812 | 'default' => 'desc', |
| @@ -1796,9 +1836,9 @@ | ||
| 1796 | 1836 | ], |
| 1797 | 1837 | ], |
| 1798 | 1838 | ], |
| 1799 | 1839 | // Export forms endpoint. |
| 1800 | - 'forms/export' => [ | |
| 1840 | + 'forms/export' => [ | |
| 1801 | 1841 | 'methods' => 'POST', |
| 1802 | 1842 | 'callback' => [ Export::get_instance(), 'handle_export_form_rest' ], |
| 1803 | 1843 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1804 | 1844 | 'args' => [ |
| @@ -1820,9 +1860,9 @@ | ||
| 1820 | 1860 | ], |
| 1821 | 1861 | ], |
| 1822 | 1862 | ], |
| 1823 | 1863 | // Import forms endpoint. |
| 1824 | - 'forms/import' => [ | |
| 1864 | + 'forms/import' => [ | |
| 1825 | 1865 | 'methods' => 'POST', |
| 1826 | 1866 | 'callback' => [ Export::get_instance(), 'handle_import_form_rest' ], |
| 1827 | 1867 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1828 | 1868 | 'args' => [ |
| @@ -1842,9 +1882,9 @@ | ||
| 1842 | 1882 | ], |
| 1843 | 1883 | ], |
| 1844 | 1884 | ], |
| 1845 | 1885 | // Form lifecycle management endpoint (trash/restore/delete/draft). |
| 1846 | - 'forms/manage' => [ | |
| 1886 | + 'forms/manage' => [ | |
| 1847 | 1887 | 'methods' => 'POST', |
| 1848 | 1888 | 'callback' => [ $this, 'manage_form_lifecycle' ], |
| 1849 | 1889 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1850 | 1890 | 'args' => [ |
| @@ -1872,9 +1912,9 @@ | ||
| 1872 | 1912 | ], |
| 1873 | 1913 | ], |
| 1874 | 1914 | ], |
| 1875 | 1915 | // Form duplication endpoint. |
| 1876 | - 'forms/duplicate' => [ | |
| 1916 | + 'forms/duplicate' => [ | |
| 1877 | 1917 | 'methods' => 'POST', |
| 1878 | 1918 | 'callback' => [ Duplicate_Form::get_instance(), 'handle_duplicate_form_rest' ], |
| 1879 | 1919 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1880 | 1920 | 'args' => [ |