| @@ -84,8 +84,34 @@ | ||
| 84 | 84 | return filter_var( $value, FILTER_VALIDATE_BOOLEAN ); |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | 87 | /** |
| 88 | + * Return the visitor's detected country code. | |
| 89 | + * | |
| 90 | + * Public, read-only — resolves the country for the *current* request's IP via | |
| 91 | + * Helper::get_geo_country(), so the phone field can fetch it per-visitor and | |
| 92 | + * work on full-page-cached sites. Outbound geolocation calls are bounded by | |
| 93 | + * the hourly cap inside Helper::get_geo_country(). | |
| 94 | + * | |
| 95 | + * @since 2.11.1 | |
| 96 | + * @return \WP_REST_Response | |
| 97 | + */ | |
| 98 | + public function get_geo_country() { | |
| 99 | + // Pass an empty fallback so '' unambiguously means "not confidently | |
| 100 | + // detected" (no CDN header and no successful IP lookup). The frontend then | |
| 101 | + // falls back to a privacy-safe, network-free Intl guess in the browser. | |
| 102 | + $country = Helper::get_geo_country( '' ); | |
| 103 | + | |
| 104 | + return new \WP_REST_Response( | |
| 105 | + [ | |
| 106 | + 'country' => $country, | |
| 107 | + 'detected' => '' !== $country, | |
| 108 | + ], | |
| 109 | + 200 | |
| 110 | + ); | |
| 111 | + } | |
| 112 | + | |
| 113 | + /** | |
| 88 | 114 | * Get the data for generating entries chart. |
| 89 | 115 | * |
| 90 | 116 | * @param \WP_REST_Request $request Full details about the request. |
| 91 | 117 | * @since 1.0.0 |
| @@ -788,9 +814,9 @@ | ||
| 788 | 814 | } |
| 789 | 815 | |
| 790 | 816 | $label_parts = explode( '-lbl-', $field_name ); |
| 791 | 817 | $label = isset( $label_parts[1] ) ? explode( '-', $label_parts[1] )[0] : ''; |
| 792 | - $label = $label ? Helper::decrypt( $label ) : ''; | |
| 818 | + $label = $label ? Helper::decode( $label ) : ''; | |
| 793 | 819 | $field_block_name = Helper::get_block_name_from_field( $field_name ); |
| 794 | 820 | |
| 795 | 821 | /** |
| 796 | 822 | * Filter: 'srfm_entry_value' |
| @@ -796,9 +822,11 @@ | ||
| 796 | 822 | * Filter: 'srfm_entry_value' |
| 797 | 823 | * |
| 798 | 824 | * This filter is used to allow 3rd party plugins or custom code to modify |
| 799 | 825 | * the entry field value in the entry details REST API response, if required. |
| 800 | - * 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. | |
| 801 | 829 | * |
| 802 | 830 | * @since 2.0.0 |
| 803 | 831 | * |
| 804 | 832 | * @param mixed $value The original value for the field. |
| @@ -926,14 +954,26 @@ | ||
| 926 | 954 | foreach ( $paginated_logs as $index => $log ) { |
| 927 | 955 | if ( ! is_array( $log ) ) { |
| 928 | 956 | continue; |
| 929 | 957 | } |
| 930 | - $formatted_logs[] = [ | |
| 958 | + $formatted_log = [ | |
| 931 | 959 | 'id' => $offset + $index, // Use offset-based ID for consistent deletion. |
| 932 | 960 | 'title' => $log['title'] ?? '', |
| 933 | 961 | 'timestamp' => $log['timestamp'] ?? time(), |
| 934 | 962 | 'messages' => $log['messages'] ?? [], |
| 935 | 963 | ]; |
| 964 | + | |
| 965 | + // Pass through (sanitized) retry metadata so an integration/webhook log row can | |
| 966 | + // offer a "Retry" action for that specific failed trigger. Set by the Pro | |
| 967 | + // webhook / native-integration dispatchers as [ 'type' => webhook|native, 'id' => <trigger id> ]. | |
| 968 | + if ( isset( $log['retry'] ) && is_array( $log['retry'] ) && ! empty( $log['retry']['type'] ) && isset( $log['retry']['id'] ) ) { | |
| 969 | + $formatted_log['retry'] = [ | |
| 970 | + 'type' => sanitize_text_field( Helper::get_string_value( $log['retry']['type'] ) ), | |
| 971 | + 'id' => sanitize_text_field( Helper::get_string_value( $log['retry']['id'] ) ), | |
| 972 | + ]; | |
| 973 | + } | |
| 974 | + | |
| 975 | + $formatted_logs[] = $formatted_log; | |
| 936 | 976 | } |
| 937 | 977 | |
| 938 | 978 | $response_data = [ |
| 939 | 979 | 'logs' => $formatted_logs, |
| @@ -1200,9 +1240,9 @@ | ||
| 1200 | 1240 | $field_name = ''; |
| 1201 | 1241 | $base_field_name = ''; |
| 1202 | 1242 | |
| 1203 | 1243 | if ( ! empty( $label ) && ! empty( $slug ) && ! empty( $block_id ) ) { |
| 1204 | - $input_label = '-lbl-' . Helper::encrypt( $label ); | |
| 1244 | + $input_label = '-lbl-' . Helper::encode( $label ); | |
| 1205 | 1245 | $base_field_name = $input_label . '-' . $slug; |
| 1206 | 1246 | |
| 1207 | 1247 | // Handle special case for dropdown with instance counter. |
| 1208 | 1248 | if ( 'dropdown' === $block_type ) { |
| @@ -1356,9 +1396,9 @@ | ||
| 1356 | 1396 | */ |
| 1357 | 1397 | return apply_filters( |
| 1358 | 1398 | 'srfm_rest_api_endpoints', |
| 1359 | 1399 | [ |
| 1360 | - 'generate-form' => [ | |
| 1400 | + 'generate-form' => [ | |
| 1361 | 1401 | 'methods' => 'POST', |
| 1362 | 1402 | 'callback' => [ AI_Form_Builder::get_instance(), 'generate_ai_form' ], |
| 1363 | 1403 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1364 | 1404 | 'args' => [ |
| @@ -1367,39 +1407,126 @@ | ||
| 1367 | 1407 | ], |
| 1368 | 1408 | ], |
| 1369 | 1409 | ], |
| 1370 | 1410 | // This route is used to map the AI response to SureForms fields markup. |
| 1371 | - 'map-fields' => [ | |
| 1411 | + 'map-fields' => [ | |
| 1372 | 1412 | 'methods' => 'POST', |
| 1373 | 1413 | 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], |
| 1374 | 1414 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1375 | 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 | + ], | |
| 1376 | 1495 | // This route is used to initiate auth process when user tries to authenticate on billing portal. |
| 1377 | - 'initiate-auth' => [ | |
| 1496 | + 'initiate-auth' => [ | |
| 1378 | 1497 | 'methods' => 'GET', |
| 1379 | 1498 | 'callback' => [ AI_Auth::get_instance(), 'get_auth_url' ], |
| 1380 | 1499 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1381 | 1500 | ], |
| 1382 | 1501 | // This route is to used to decrypt the access key and save it in the database. |
| 1383 | - 'handle-access-key' => [ | |
| 1502 | + 'handle-access-key' => [ | |
| 1384 | 1503 | 'methods' => 'POST', |
| 1385 | 1504 | 'callback' => [ AI_Auth::get_instance(), 'handle_access_key' ], |
| 1386 | 1505 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1387 | 1506 | ], |
| 1507 | + // Public route: returns the visitor's detected country code. Called | |
| 1508 | + // per-visitor from the phone field so auto-country detection works | |
| 1509 | + // on full-page-cached sites (the value isn't baked into cached HTML). | |
| 1510 | + 'geo-country' => [ | |
| 1511 | + 'methods' => 'GET', | |
| 1512 | + 'callback' => [ $this, 'get_geo_country' ], | |
| 1513 | + 'permission_callback' => '__return_true', | |
| 1514 | + ], | |
| 1388 | 1515 | // This route is to get the form submissions for the last 30 days. |
| 1389 | - 'entries-chart-data' => [ | |
| 1516 | + 'entries-chart-data' => [ | |
| 1390 | 1517 | 'methods' => 'GET', |
| 1391 | 1518 | 'callback' => [ $this, 'get_entries_chart_data' ], |
| 1392 | 1519 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1393 | 1520 | ], |
| 1394 | 1521 | // This route is to get all forms data. |
| 1395 | - 'form-data' => [ | |
| 1522 | + 'form-data' => [ | |
| 1396 | 1523 | 'methods' => 'GET', |
| 1397 | 1524 | 'callback' => [ $this, 'get_form_data' ], |
| 1398 | 1525 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1399 | 1526 | ], |
| 1400 | 1527 | // Page search endpoint for async admin dropdowns. |
| 1401 | - 'pages/search' => [ | |
| 1528 | + 'pages/search' => [ | |
| 1402 | 1529 | 'methods' => 'GET', |
| 1403 | 1530 | 'callback' => [ $this, 'search_pages' ], |
| 1404 | 1531 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1405 | 1532 | 'args' => [ |
| @@ -1449,19 +1576,19 @@ | ||
| 1449 | 1576 | ], |
| 1450 | 1577 | ], |
| 1451 | 1578 | ], |
| 1452 | 1579 | // Onboarding endpoints. |
| 1453 | - 'onboarding/set-status' => [ | |
| 1580 | + 'onboarding/set-status' => [ | |
| 1454 | 1581 | 'methods' => 'POST', |
| 1455 | 1582 | 'callback' => [ $this, 'set_onboarding_status' ], |
| 1456 | 1583 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1457 | 1584 | ], |
| 1458 | - 'onboarding/get-status' => [ | |
| 1585 | + 'onboarding/get-status' => [ | |
| 1459 | 1586 | 'methods' => 'GET', |
| 1460 | 1587 | 'callback' => [ $this, 'get_onboarding_status' ], |
| 1461 | 1588 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1462 | 1589 | ], |
| 1463 | - 'onboarding/user-details' => [ | |
| 1590 | + 'onboarding/user-details' => [ | |
| 1464 | 1591 | 'methods' => 'POST', |
| 1465 | 1592 | 'callback' => [ $this, 'save_onboarding_user_details' ], |
| 1466 | 1593 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1467 | 1594 | 'args' => [ |
| @@ -1485,9 +1612,9 @@ | ||
| 1485 | 1612 | ], |
| 1486 | 1613 | ], |
| 1487 | 1614 | ], |
| 1488 | 1615 | // Plugin status endpoint. |
| 1489 | - 'plugin-status' => [ | |
| 1616 | + 'plugin-status' => [ | |
| 1490 | 1617 | 'methods' => 'GET', |
| 1491 | 1618 | 'callback' => [ $this, 'get_plugin_status' ], |
| 1492 | 1619 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1493 | 1620 | 'args' => [ |
| @@ -1497,9 +1624,9 @@ | ||
| 1497 | 1624 | ], |
| 1498 | 1625 | ], |
| 1499 | 1626 | ], |
| 1500 | 1627 | // Entries endpoints. |
| 1501 | - 'entries/list' => [ | |
| 1628 | + 'entries/list' => [ | |
| 1502 | 1629 | 'methods' => 'GET', |
| 1503 | 1630 | 'callback' => [ $this, 'get_entries_list' ], |
| 1504 | 1631 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1505 | 1632 | 'args' => [ |
| @@ -1544,9 +1671,9 @@ | ||
| 1544 | 1671 | 'default' => 1, |
| 1545 | 1672 | ], |
| 1546 | 1673 | ], |
| 1547 | 1674 | ], |
| 1548 | - 'entries/read-status' => [ | |
| 1675 | + 'entries/read-status' => [ | |
| 1549 | 1676 | 'methods' => 'POST', |
| 1550 | 1677 | 'callback' => [ $this, 'update_entries_read_status' ], |
| 1551 | 1678 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1552 | 1679 | 'args' => [ |
| @@ -1560,9 +1687,9 @@ | ||
| 1560 | 1687 | 'validate_callback' => [ $this, 'validate_read_action' ], |
| 1561 | 1688 | ], |
| 1562 | 1689 | ], |
| 1563 | 1690 | ], |
| 1564 | - 'entries/trash' => [ | |
| 1691 | + 'entries/trash' => [ | |
| 1565 | 1692 | 'methods' => 'POST', |
| 1566 | 1693 | 'callback' => [ $this, 'update_entries_trash_status' ], |
| 1567 | 1694 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1568 | 1695 | 'args' => [ |
| @@ -1576,9 +1703,9 @@ | ||
| 1576 | 1703 | 'validate_callback' => [ $this, 'validate_trash_action' ], |
| 1577 | 1704 | ], |
| 1578 | 1705 | ], |
| 1579 | 1706 | ], |
| 1580 | - 'entries/delete' => [ | |
| 1707 | + 'entries/delete' => [ | |
| 1581 | 1708 | 'methods' => 'POST', |
| 1582 | 1709 | 'callback' => [ $this, 'delete_entries' ], |
| 1583 | 1710 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1584 | 1711 | 'args' => [ |
| @@ -1587,9 +1714,9 @@ | ||
| 1587 | 1714 | 'sanitize_callback' => [ $this, 'sanitize_entry_ids' ], |
| 1588 | 1715 | ], |
| 1589 | 1716 | ], |
| 1590 | 1717 | ], |
| 1591 | - 'entries/export' => [ | |
| 1718 | + 'entries/export' => [ | |
| 1592 | 1719 | 'methods' => 'POST', |
| 1593 | 1720 | 'callback' => [ $this, 'export_entries' ], |
| 1594 | 1721 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1595 | 1722 | 'args' => [ |
| @@ -1619,9 +1746,9 @@ | ||
| 1619 | 1746 | ], |
| 1620 | 1747 | ], |
| 1621 | 1748 | ], |
| 1622 | 1749 | // Get Single Entry Form Data. |
| 1623 | - 'entry/(?P<id>\d+)/details' => [ | |
| 1750 | + 'entry/(?P<id>\d+)/details' => [ | |
| 1624 | 1751 | 'methods' => 'GET', |
| 1625 | 1752 | 'callback' => [ $this, 'get_entry_details' ], |
| 1626 | 1753 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1627 | 1754 | 'args' => [ |
| @@ -1631,9 +1758,9 @@ | ||
| 1631 | 1758 | ], |
| 1632 | 1759 | ], |
| 1633 | 1760 | ], |
| 1634 | 1761 | // Get Single Entry Logs. |
| 1635 | - 'entry/(?P<id>\d+)/logs' => [ | |
| 1762 | + 'entry/(?P<id>\d+)/logs' => [ | |
| 1636 | 1763 | 'methods' => 'GET', |
| 1637 | 1764 | 'callback' => [ $this, 'get_entry_logs' ], |
| 1638 | 1765 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1639 | 1766 | 'args' => [ |
| @@ -1651,9 +1778,9 @@ | ||
| 1651 | 1778 | ], |
| 1652 | 1779 | ], |
| 1653 | 1780 | ], |
| 1654 | 1781 | // Forms listing endpoint. |
| 1655 | - 'forms' => [ | |
| 1782 | + 'forms' => [ | |
| 1656 | 1783 | 'methods' => 'GET', |
| 1657 | 1784 | 'callback' => [ Forms_Data::get_instance(), 'get_forms_list' ], |
| 1658 | 1785 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1659 | 1786 | 'args' => [ |
| @@ -1677,9 +1804,9 @@ | ||
| 1677 | 1804 | ], |
| 1678 | 1805 | 'orderby' => [ |
| 1679 | 1806 | 'type' => 'string', |
| 1680 | 1807 | 'default' => 'date', |
| 1681 | - 'enum' => [ 'date', 'id', 'title', 'modified' ], | |
| 1808 | + 'enum' => [ 'date', 'id', 'title', 'modified', 'views', 'conversion_rate' ], | |
| 1682 | 1809 | ], |
| 1683 | 1810 | 'order' => [ |
| 1684 | 1811 | 'type' => 'string', |
| 1685 | 1812 | 'default' => 'desc', |
| @@ -1709,9 +1836,9 @@ | ||
| 1709 | 1836 | ], |
| 1710 | 1837 | ], |
| 1711 | 1838 | ], |
| 1712 | 1839 | // Export forms endpoint. |
| 1713 | - 'forms/export' => [ | |
| 1840 | + 'forms/export' => [ | |
| 1714 | 1841 | 'methods' => 'POST', |
| 1715 | 1842 | 'callback' => [ Export::get_instance(), 'handle_export_form_rest' ], |
| 1716 | 1843 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1717 | 1844 | 'args' => [ |
| @@ -1733,9 +1860,9 @@ | ||
| 1733 | 1860 | ], |
| 1734 | 1861 | ], |
| 1735 | 1862 | ], |
| 1736 | 1863 | // Import forms endpoint. |
| 1737 | - 'forms/import' => [ | |
| 1864 | + 'forms/import' => [ | |
| 1738 | 1865 | 'methods' => 'POST', |
| 1739 | 1866 | 'callback' => [ Export::get_instance(), 'handle_import_form_rest' ], |
| 1740 | 1867 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1741 | 1868 | 'args' => [ |
| @@ -1755,9 +1882,9 @@ | ||
| 1755 | 1882 | ], |
| 1756 | 1883 | ], |
| 1757 | 1884 | ], |
| 1758 | 1885 | // Form lifecycle management endpoint (trash/restore/delete/draft). |
| 1759 | - 'forms/manage' => [ | |
| 1886 | + 'forms/manage' => [ | |
| 1760 | 1887 | 'methods' => 'POST', |
| 1761 | 1888 | 'callback' => [ $this, 'manage_form_lifecycle' ], |
| 1762 | 1889 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1763 | 1890 | 'args' => [ |
| @@ -1785,9 +1912,9 @@ | ||
| 1785 | 1912 | ], |
| 1786 | 1913 | ], |
| 1787 | 1914 | ], |
| 1788 | 1915 | // Form duplication endpoint. |
| 1789 | - 'forms/duplicate' => [ | |
| 1916 | + 'forms/duplicate' => [ | |
| 1790 | 1917 | 'methods' => 'POST', |
| 1791 | 1918 | 'callback' => [ Duplicate_Form::get_instance(), 'handle_duplicate_form_rest' ], |
| 1792 | 1919 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1793 | 1920 | 'args' => [ |