| @@ -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. |
| @@ -850,11 +878,14 @@ | ||
| 850 | 878 | 'created_at' => $entry['created_at'], |
| 851 | 879 | 'form_data' => $form_data, |
| 852 | 880 | 'form_content' => $form_fields, |
| 853 | 881 | 'submission_info' => [ |
| 854 | - 'user_ip' => $entry['submission_info']['user_ip'] ?? '', | |
| 855 | - 'browser_name' => $entry['submission_info']['browser_name'] ?? '', | |
| 856 | - 'device_name' => $entry['submission_info']['device_name'] ?? '', | |
| 882 | + 'user_ip' => $entry['submission_info']['user_ip'] ?? '', | |
| 883 | + 'browser_name' => $entry['submission_info']['browser_name'] ?? '', | |
| 884 | + 'device_name' => $entry['submission_info']['device_name'] ?? '', | |
| 885 | + // Re-sanitize at the exposure boundary in case the stored value | |
| 886 | + // was written by a future code path that bypasses form-submit.php. | |
| 887 | + 'submission_url' => esc_url_raw( $entry['submission_info']['submission_url'] ?? '', [ 'http', 'https' ] ), | |
| 857 | 888 | ], |
| 858 | 889 | 'user' => $user_info ? [ |
| 859 | 890 | 'id' => $user_id, |
| 860 | 891 | 'display_name' => $user_info->display_name, |
| @@ -923,14 +954,26 @@ | ||
| 923 | 954 | foreach ( $paginated_logs as $index => $log ) { |
| 924 | 955 | if ( ! is_array( $log ) ) { |
| 925 | 956 | continue; |
| 926 | 957 | } |
| 927 | - $formatted_logs[] = [ | |
| 958 | + $formatted_log = [ | |
| 928 | 959 | 'id' => $offset + $index, // Use offset-based ID for consistent deletion. |
| 929 | 960 | 'title' => $log['title'] ?? '', |
| 930 | 961 | 'timestamp' => $log['timestamp'] ?? time(), |
| 931 | 962 | 'messages' => $log['messages'] ?? [], |
| 932 | 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; | |
| 933 | 976 | } |
| 934 | 977 | |
| 935 | 978 | $response_data = [ |
| 936 | 979 | 'logs' => $formatted_logs, |
| @@ -1078,8 +1121,29 @@ | ||
| 1078 | 1121 | // Force delete permanently. |
| 1079 | 1122 | $result = wp_delete_post( $form_id, true ); |
| 1080 | 1123 | break; |
| 1081 | 1124 | |
| 1125 | + case 'draft': | |
| 1126 | + if ( 'trash' === $post->post_status ) { | |
| 1127 | + $errors[] = [ | |
| 1128 | + 'form_id' => $form_id, | |
| 1129 | + 'error' => __( 'Use the restore action to recover a trashed form before switching it to draft.', 'sureforms' ), | |
| 1130 | + ]; | |
| 1131 | + } elseif ( 'draft' === $post->post_status ) { | |
| 1132 | + $errors[] = [ | |
| 1133 | + 'form_id' => $form_id, | |
| 1134 | + 'error' => __( 'This form is already a draft.', 'sureforms' ), | |
| 1135 | + ]; | |
| 1136 | + } else { | |
| 1137 | + $result = wp_update_post( | |
| 1138 | + [ | |
| 1139 | + 'ID' => $form_id, | |
| 1140 | + 'post_status' => 'draft', | |
| 1141 | + ] | |
| 1142 | + ); | |
| 1143 | + } | |
| 1144 | + break; | |
| 1145 | + | |
| 1082 | 1146 | default: |
| 1083 | 1147 | $errors[] = [ |
| 1084 | 1148 | 'form_id' => $form_id, |
| 1085 | 1149 | 'error' => __( 'Invalid action.', 'sureforms' ), |
| @@ -1176,9 +1240,9 @@ | ||
| 1176 | 1240 | $field_name = ''; |
| 1177 | 1241 | $base_field_name = ''; |
| 1178 | 1242 | |
| 1179 | 1243 | if ( ! empty( $label ) && ! empty( $slug ) && ! empty( $block_id ) ) { |
| 1180 | - $input_label = '-lbl-' . Helper::encrypt( $label ); | |
| 1244 | + $input_label = '-lbl-' . Helper::encode( $label ); | |
| 1181 | 1245 | $base_field_name = $input_label . '-' . $slug; |
| 1182 | 1246 | |
| 1183 | 1247 | // Handle special case for dropdown with instance counter. |
| 1184 | 1248 | if ( 'dropdown' === $block_type ) { |
| @@ -1332,9 +1396,9 @@ | ||
| 1332 | 1396 | */ |
| 1333 | 1397 | return apply_filters( |
| 1334 | 1398 | 'srfm_rest_api_endpoints', |
| 1335 | 1399 | [ |
| 1336 | - 'generate-form' => [ | |
| 1400 | + 'generate-form' => [ | |
| 1337 | 1401 | 'methods' => 'POST', |
| 1338 | 1402 | 'callback' => [ AI_Form_Builder::get_instance(), 'generate_ai_form' ], |
| 1339 | 1403 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1340 | 1404 | 'args' => [ |
| @@ -1343,39 +1407,126 @@ | ||
| 1343 | 1407 | ], |
| 1344 | 1408 | ], |
| 1345 | 1409 | ], |
| 1346 | 1410 | // This route is used to map the AI response to SureForms fields markup. |
| 1347 | - 'map-fields' => [ | |
| 1411 | + 'map-fields' => [ | |
| 1348 | 1412 | 'methods' => 'POST', |
| 1349 | 1413 | 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], |
| 1350 | 1414 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1351 | 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 | + ], | |
| 1352 | 1495 | // This route is used to initiate auth process when user tries to authenticate on billing portal. |
| 1353 | - 'initiate-auth' => [ | |
| 1496 | + 'initiate-auth' => [ | |
| 1354 | 1497 | 'methods' => 'GET', |
| 1355 | 1498 | 'callback' => [ AI_Auth::get_instance(), 'get_auth_url' ], |
| 1356 | 1499 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1357 | 1500 | ], |
| 1358 | 1501 | // This route is to used to decrypt the access key and save it in the database. |
| 1359 | - 'handle-access-key' => [ | |
| 1502 | + 'handle-access-key' => [ | |
| 1360 | 1503 | 'methods' => 'POST', |
| 1361 | 1504 | 'callback' => [ AI_Auth::get_instance(), 'handle_access_key' ], |
| 1362 | 1505 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1363 | 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 | + ], | |
| 1364 | 1515 | // This route is to get the form submissions for the last 30 days. |
| 1365 | - 'entries-chart-data' => [ | |
| 1516 | + 'entries-chart-data' => [ | |
| 1366 | 1517 | 'methods' => 'GET', |
| 1367 | 1518 | 'callback' => [ $this, 'get_entries_chart_data' ], |
| 1368 | 1519 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1369 | 1520 | ], |
| 1370 | 1521 | // This route is to get all forms data. |
| 1371 | - 'form-data' => [ | |
| 1522 | + 'form-data' => [ | |
| 1372 | 1523 | 'methods' => 'GET', |
| 1373 | 1524 | 'callback' => [ $this, 'get_form_data' ], |
| 1374 | 1525 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1375 | 1526 | ], |
| 1376 | 1527 | // Page search endpoint for async admin dropdowns. |
| 1377 | - 'pages/search' => [ | |
| 1528 | + 'pages/search' => [ | |
| 1378 | 1529 | 'methods' => 'GET', |
| 1379 | 1530 | 'callback' => [ $this, 'search_pages' ], |
| 1380 | 1531 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1381 | 1532 | 'args' => [ |
| @@ -1425,19 +1576,19 @@ | ||
| 1425 | 1576 | ], |
| 1426 | 1577 | ], |
| 1427 | 1578 | ], |
| 1428 | 1579 | // Onboarding endpoints. |
| 1429 | - 'onboarding/set-status' => [ | |
| 1580 | + 'onboarding/set-status' => [ | |
| 1430 | 1581 | 'methods' => 'POST', |
| 1431 | 1582 | 'callback' => [ $this, 'set_onboarding_status' ], |
| 1432 | 1583 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1433 | 1584 | ], |
| 1434 | - 'onboarding/get-status' => [ | |
| 1585 | + 'onboarding/get-status' => [ | |
| 1435 | 1586 | 'methods' => 'GET', |
| 1436 | 1587 | 'callback' => [ $this, 'get_onboarding_status' ], |
| 1437 | 1588 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1438 | 1589 | ], |
| 1439 | - 'onboarding/user-details' => [ | |
| 1590 | + 'onboarding/user-details' => [ | |
| 1440 | 1591 | 'methods' => 'POST', |
| 1441 | 1592 | 'callback' => [ $this, 'save_onboarding_user_details' ], |
| 1442 | 1593 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1443 | 1594 | 'args' => [ |
| @@ -1461,9 +1612,9 @@ | ||
| 1461 | 1612 | ], |
| 1462 | 1613 | ], |
| 1463 | 1614 | ], |
| 1464 | 1615 | // Plugin status endpoint. |
| 1465 | - 'plugin-status' => [ | |
| 1616 | + 'plugin-status' => [ | |
| 1466 | 1617 | 'methods' => 'GET', |
| 1467 | 1618 | 'callback' => [ $this, 'get_plugin_status' ], |
| 1468 | 1619 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1469 | 1620 | 'args' => [ |
| @@ -1473,9 +1624,9 @@ | ||
| 1473 | 1624 | ], |
| 1474 | 1625 | ], |
| 1475 | 1626 | ], |
| 1476 | 1627 | // Entries endpoints. |
| 1477 | - 'entries/list' => [ | |
| 1628 | + 'entries/list' => [ | |
| 1478 | 1629 | 'methods' => 'GET', |
| 1479 | 1630 | 'callback' => [ $this, 'get_entries_list' ], |
| 1480 | 1631 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1481 | 1632 | 'args' => [ |
| @@ -1520,9 +1671,9 @@ | ||
| 1520 | 1671 | 'default' => 1, |
| 1521 | 1672 | ], |
| 1522 | 1673 | ], |
| 1523 | 1674 | ], |
| 1524 | - 'entries/read-status' => [ | |
| 1675 | + 'entries/read-status' => [ | |
| 1525 | 1676 | 'methods' => 'POST', |
| 1526 | 1677 | 'callback' => [ $this, 'update_entries_read_status' ], |
| 1527 | 1678 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1528 | 1679 | 'args' => [ |
| @@ -1536,9 +1687,9 @@ | ||
| 1536 | 1687 | 'validate_callback' => [ $this, 'validate_read_action' ], |
| 1537 | 1688 | ], |
| 1538 | 1689 | ], |
| 1539 | 1690 | ], |
| 1540 | - 'entries/trash' => [ | |
| 1691 | + 'entries/trash' => [ | |
| 1541 | 1692 | 'methods' => 'POST', |
| 1542 | 1693 | 'callback' => [ $this, 'update_entries_trash_status' ], |
| 1543 | 1694 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1544 | 1695 | 'args' => [ |
| @@ -1552,9 +1703,9 @@ | ||
| 1552 | 1703 | 'validate_callback' => [ $this, 'validate_trash_action' ], |
| 1553 | 1704 | ], |
| 1554 | 1705 | ], |
| 1555 | 1706 | ], |
| 1556 | - 'entries/delete' => [ | |
| 1707 | + 'entries/delete' => [ | |
| 1557 | 1708 | 'methods' => 'POST', |
| 1558 | 1709 | 'callback' => [ $this, 'delete_entries' ], |
| 1559 | 1710 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1560 | 1711 | 'args' => [ |
| @@ -1563,9 +1714,9 @@ | ||
| 1563 | 1714 | 'sanitize_callback' => [ $this, 'sanitize_entry_ids' ], |
| 1564 | 1715 | ], |
| 1565 | 1716 | ], |
| 1566 | 1717 | ], |
| 1567 | - 'entries/export' => [ | |
| 1718 | + 'entries/export' => [ | |
| 1568 | 1719 | 'methods' => 'POST', |
| 1569 | 1720 | 'callback' => [ $this, 'export_entries' ], |
| 1570 | 1721 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1571 | 1722 | 'args' => [ |
| @@ -1595,9 +1746,9 @@ | ||
| 1595 | 1746 | ], |
| 1596 | 1747 | ], |
| 1597 | 1748 | ], |
| 1598 | 1749 | // Get Single Entry Form Data. |
| 1599 | - 'entry/(?P<id>\d+)/details' => [ | |
| 1750 | + 'entry/(?P<id>\d+)/details' => [ | |
| 1600 | 1751 | 'methods' => 'GET', |
| 1601 | 1752 | 'callback' => [ $this, 'get_entry_details' ], |
| 1602 | 1753 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1603 | 1754 | 'args' => [ |
| @@ -1607,9 +1758,9 @@ | ||
| 1607 | 1758 | ], |
| 1608 | 1759 | ], |
| 1609 | 1760 | ], |
| 1610 | 1761 | // Get Single Entry Logs. |
| 1611 | - 'entry/(?P<id>\d+)/logs' => [ | |
| 1762 | + 'entry/(?P<id>\d+)/logs' => [ | |
| 1612 | 1763 | 'methods' => 'GET', |
| 1613 | 1764 | 'callback' => [ $this, 'get_entry_logs' ], |
| 1614 | 1765 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1615 | 1766 | 'args' => [ |
| @@ -1627,9 +1778,9 @@ | ||
| 1627 | 1778 | ], |
| 1628 | 1779 | ], |
| 1629 | 1780 | ], |
| 1630 | 1781 | // Forms listing endpoint. |
| 1631 | - 'forms' => [ | |
| 1782 | + 'forms' => [ | |
| 1632 | 1783 | 'methods' => 'GET', |
| 1633 | 1784 | 'callback' => [ Forms_Data::get_instance(), 'get_forms_list' ], |
| 1634 | 1785 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1635 | 1786 | 'args' => [ |
| @@ -1653,9 +1804,9 @@ | ||
| 1653 | 1804 | ], |
| 1654 | 1805 | 'orderby' => [ |
| 1655 | 1806 | 'type' => 'string', |
| 1656 | 1807 | 'default' => 'date', |
| 1657 | - 'enum' => [ 'date', 'id', 'title', 'modified' ], | |
| 1808 | + 'enum' => [ 'date', 'id', 'title', 'modified', 'views', 'conversion_rate' ], | |
| 1658 | 1809 | ], |
| 1659 | 1810 | 'order' => [ |
| 1660 | 1811 | 'type' => 'string', |
| 1661 | 1812 | 'default' => 'desc', |
| @@ -1685,9 +1836,9 @@ | ||
| 1685 | 1836 | ], |
| 1686 | 1837 | ], |
| 1687 | 1838 | ], |
| 1688 | 1839 | // Export forms endpoint. |
| 1689 | - 'forms/export' => [ | |
| 1840 | + 'forms/export' => [ | |
| 1690 | 1841 | 'methods' => 'POST', |
| 1691 | 1842 | 'callback' => [ Export::get_instance(), 'handle_export_form_rest' ], |
| 1692 | 1843 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1693 | 1844 | 'args' => [ |
| @@ -1709,9 +1860,9 @@ | ||
| 1709 | 1860 | ], |
| 1710 | 1861 | ], |
| 1711 | 1862 | ], |
| 1712 | 1863 | // Import forms endpoint. |
| 1713 | - 'forms/import' => [ | |
| 1864 | + 'forms/import' => [ | |
| 1714 | 1865 | 'methods' => 'POST', |
| 1715 | 1866 | 'callback' => [ Export::get_instance(), 'handle_import_form_rest' ], |
| 1716 | 1867 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1717 | 1868 | 'args' => [ |
| @@ -1730,10 +1881,10 @@ | ||
| 1730 | 1881 | 'sanitize_callback' => 'sanitize_text_field', |
| 1731 | 1882 | ], |
| 1732 | 1883 | ], |
| 1733 | 1884 | ], |
| 1734 | - // Form lifecycle management endpoint (trash/restore/delete). | |
| 1735 | - 'forms/manage' => [ | |
| 1885 | + // Form lifecycle management endpoint (trash/restore/delete/draft). | |
| 1886 | + 'forms/manage' => [ | |
| 1736 | 1887 | 'methods' => 'POST', |
| 1737 | 1888 | 'callback' => [ $this, 'manage_form_lifecycle' ], |
| 1738 | 1889 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1739 | 1890 | 'args' => [ |
| @@ -1755,15 +1906,15 @@ | ||
| 1755 | 1906 | ], |
| 1756 | 1907 | 'action' => [ |
| 1757 | 1908 | 'required' => true, |
| 1758 | 1909 | 'type' => 'string', |
| 1759 | - 'enum' => [ 'trash', 'restore', 'delete' ], | |
| 1910 | + 'enum' => [ 'trash', 'restore', 'delete', 'draft' ], | |
| 1760 | 1911 | 'sanitize_callback' => 'sanitize_text_field', |
| 1761 | 1912 | ], |
| 1762 | 1913 | ], |
| 1763 | 1914 | ], |
| 1764 | 1915 | // Form duplication endpoint. |
| 1765 | - 'forms/duplicate' => [ | |
| 1916 | + 'forms/duplicate' => [ | |
| 1766 | 1917 | 'methods' => 'POST', |
| 1767 | 1918 | 'callback' => [ Duplicate_Form::get_instance(), 'handle_duplicate_form_rest' ], |
| 1768 | 1919 | 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], |
| 1769 | 1920 | 'args' => [ |