@@ -1692,55 +1692,60 @@ public function get_collection_params() {
1692
1692
// Date params starts here.
1693
1693
$ params ['year ' ] = array (
1694
1694
'description ' => __ ( '4 digit year (e.g. 2011). ' ),
1695
- 'type ' => 'int ' ,
1695
+ 'type ' => 'integer ' ,
1696
1696
'validate_callback ' => 'rest_validate_request_arg ' ,
1697
- 'sanitize_callback ' => 'absint ' ,
1698
1697
);
1699
1698
$ params ['monthnum ' ] = array (
1700
1699
'description ' => __ ( 'Month number (from 1 to 12). ' ),
1701
- 'type ' => 'int ' ,
1700
+ 'type ' => 'integer ' ,
1701
+ 'minimum ' => 1 ,
1702
+ 'maximum ' => 12 ,
1702
1703
'validate_callback ' => 'rest_validate_request_arg ' ,
1703
- 'sanitize_callback ' => 'absint ' ,
1704
1704
);
1705
1705
$ params ['w ' ] = array (
1706
1706
'description ' => __ ( 'Week of the year (from 0 to 53). Uses MySQL WEEK command. The mode is dependent on the "start_of_week" option. ' ),
1707
- 'type ' => 'int ' ,
1707
+ 'type ' => 'integer ' ,
1708
+ 'minimum ' => 0 ,
1709
+ 'maximum ' => 53 ,
1708
1710
'validate_callback ' => 'rest_validate_request_arg ' ,
1709
- 'sanitize_callback ' => 'absint ' ,
1710
1711
);
1711
1712
$ params ['day ' ] = array (
1712
1713
'description ' => __ ( 'Day of the month (from 1 to 31). ' ),
1713
- 'type ' => 'int ' ,
1714
+ 'type ' => 'integer ' ,
1715
+ 'minimum ' => 1 ,
1716
+ 'maximum ' => 31 ,
1714
1717
'validate_callback ' => 'rest_validate_request_arg ' ,
1715
- 'sanitize_callback ' => 'absint ' ,
1716
1718
);
1717
1719
$ params ['hour ' ] = array (
1718
1720
'description ' => __ ( 'Hour (from 0 to 23). ' ),
1719
- 'type ' => 'int ' ,
1721
+ 'type ' => 'integer ' ,
1722
+ 'minimum ' => 0 ,
1723
+ 'maximum ' => 23 ,
1720
1724
'validate_callback ' => 'rest_validate_request_arg ' ,
1721
- 'sanitize_callback ' => 'absint ' ,
1722
1725
);
1723
1726
$ params ['minute ' ] = array (
1724
1727
'description ' => __ ( 'Minute (from 0 to 60) ' ),
1725
- 'type ' => 'int ' ,
1728
+ 'type ' => 'integer ' ,
1729
+ 'minimum ' => 0 ,
1730
+ 'maximum ' => 60 ,
1726
1731
'validate_callback ' => 'rest_validate_request_arg ' ,
1727
- 'sanitize_callback ' => 'absint ' ,
1728
1732
);
1729
1733
$ params ['second ' ] = array (
1730
1734
'description ' => __ ( 'Second (0 to 60). ' ),
1731
- 'type ' => 'int ' ,
1735
+ 'type ' => 'integer ' ,
1736
+ 'minimum ' => 0 ,
1737
+ 'maximum ' => 60 ,
1732
1738
'validate_callback ' => 'rest_validate_request_arg ' ,
1733
- 'sanitize_callback ' => 'absint ' ,
1734
1739
);
1735
1740
$ params ['m ' ] = array (
1736
1741
'description ' => __ ( 'YearMonth (For e.g.: 201307). ' ),
1737
- 'type ' => 'int ' ,
1742
+ 'type ' => 'integer ' ,
1738
1743
'validate_callback ' => 'rest_validate_request_arg ' ,
1739
- 'sanitize_callback ' => 'absint ' ,
1740
1744
);
1741
1745
$ params ['date_query ' ] = array (
1742
1746
'description ' => __ ( 'Date parameters. Make sure parameters are encapsulated in an array. See wp-includes/date.php for more info or check WP_Date_Query code reference. ' ),
1743
1747
'type ' => 'array ' ,
1748
+ 'validate_callback ' => array ( $ this , 'rest_validate_date_query ' ),
1744
1749
);
1745
1750
return $ params ;
1746
1751
}
@@ -1763,4 +1768,204 @@ public function validate_user_can_query_private_statuses( $value, $request, $par
1763
1768
}
1764
1769
return new WP_Error ( 'rest_forbidden_status ' , __ ( 'Status is forbidden ' ), array ( 'status ' => rest_authorization_required_code () ) );
1765
1770
}
1771
+
1772
+ /**
1773
+ * Validate a request date query.
1774
+ *
1775
+ * @param mixed $value Value of the argument.
1776
+ * @param WP_REST_Request $request Request body.
1777
+ * @param string $param Argument name should be date_query
1778
+ * @return WP_Error|boolean
1779
+ */
1780
+ public function rest_validate_date_query ( $ value , $ request , $ param ) {
1781
+ if ( 'date_query ' !== $ param ) {
1782
+ return new WP_Error ( 'date-query-not-validated ' , __ ( 'You are validating a date query on a non date query parameter. ' ), array ( 'status ' => 400 ) );
1783
+ }
1784
+
1785
+ if ( empty ( $ value ) ) {
1786
+ return new WP_Error ( 'empty-date-query ' , __ ( 'Date query parameter is empty. Please revise your request. ' ), array ( 'status ' => 400 ) );
1787
+ }
1788
+
1789
+ if ( ! is_array ( $ value ) ) {
1790
+ return new WP_Error ( 'date-query-improperly-formatted ' , __ ( 'Date query must be formatted as an array of array(s). ' ), array ( 'status ' => 400 ) );
1791
+ }
1792
+
1793
+ $ valid = true ;
1794
+ foreach ( $ value as $ value ) {
1795
+ /*
1796
+ * Validate 'before' and 'after' up front, then let the
1797
+ * validation routine continue to be sure that all invalid
1798
+ * values generate errors too.
1799
+ */
1800
+ if ( array_key_exists ( 'before ' , $ value ) && is_array ( $ value ['before ' ] ) ) {
1801
+ $ valid = $ this ->rest_validate_date_query ( $ value ['before ' ], $ request , $ param );
1802
+ }
1803
+
1804
+ if ( array_key_exists ( 'after ' , $ value ) && is_array ( $ value ['after ' ] ) ) {
1805
+ $ valid = $ this ->rest_validate_date_query ( $ value ['after ' ], $ request , $ param );
1806
+ }
1807
+
1808
+ // Array containing all min-max checks.
1809
+ $ min_max_checks = array ();
1810
+
1811
+ // Days per year.
1812
+ if ( array_key_exists ( 'year ' , $ value ) ) {
1813
+ if ( ! is_numeric ( $ value ['year ' ] ) ) {
1814
+ return new WP_Error ( 'year-type-error ' , __ ( 'Year must be an integer representing 4 digit year. ' ), array ( 'status ' => 400 ) );
1815
+ }
1816
+ /*
1817
+ * If a year exists in the date query, we can use it to get the days.
1818
+ * If multiple years are provided (as in a BETWEEN), use the first one.
1819
+ */
1820
+ if ( is_array ( $ value ['year ' ] ) ) {
1821
+ $ _year = reset ( $ value ['year ' ] );
1822
+ } else {
1823
+ $ _year = $ value ['year ' ];
1824
+ }
1825
+
1826
+ $ max_days_of_year = date ( 'z ' , mktime ( 0 , 0 , 0 , 12 , 31 , $ _year ) ) + 1 ;
1827
+ } else {
1828
+ // otherwise we use the max of 366 (leap-year)
1829
+ $ max_days_of_year = 366 ;
1830
+ }
1831
+
1832
+ $ min_max_checks ['dayofyear ' ] = array (
1833
+ 'min ' => 1 ,
1834
+ 'max ' => $ max_days_of_year ,
1835
+ );
1836
+
1837
+ // Days per week.
1838
+ $ min_max_checks ['dayofweek ' ] = array (
1839
+ 'min ' => 1 ,
1840
+ 'max ' => 7 ,
1841
+ );
1842
+
1843
+ // Days per week.
1844
+ $ min_max_checks ['dayofweek_iso ' ] = array (
1845
+ 'min ' => 1 ,
1846
+ 'max ' => 7 ,
1847
+ );
1848
+
1849
+ // Months per year.
1850
+ $ min_max_checks ['month ' ] = array (
1851
+ 'min ' => 1 ,
1852
+ 'max ' => 12 ,
1853
+ );
1854
+
1855
+ // Weeks per year.
1856
+ if ( isset ( $ _year ) ) {
1857
+ /*
1858
+ * If we have a specific year, use it to calculate number of weeks.
1859
+ * Note: the number of weeks in a year is the date in which Dec 28 appears.
1860
+ */
1861
+ $ week_count = date ( 'W ' , mktime ( 0 , 0 , 0 , 12 , 28 , $ _year ) );
1862
+
1863
+ } else {
1864
+ // Otherwise set the week-count to a maximum of 53.
1865
+ $ week_count = 53 ;
1866
+ }
1867
+
1868
+ $ min_max_checks ['week ' ] = array (
1869
+ 'min ' => 1 ,
1870
+ 'max ' => $ week_count ,
1871
+ );
1872
+
1873
+ // Days per month.
1874
+ $ min_max_checks ['day ' ] = array (
1875
+ 'min ' => 1 ,
1876
+ 'max ' => 31 ,
1877
+ );
1878
+
1879
+ // Hours per day.
1880
+ $ min_max_checks ['hour ' ] = array (
1881
+ 'min ' => 0 ,
1882
+ 'max ' => 23 ,
1883
+ );
1884
+
1885
+ // Minutes per hour.
1886
+ $ min_max_checks ['minute ' ] = array (
1887
+ 'min ' => 0 ,
1888
+ 'max ' => 59 ,
1889
+ );
1890
+
1891
+ // Seconds per minute.
1892
+ $ min_max_checks ['second ' ] = array (
1893
+ 'min ' => 0 ,
1894
+ 'max ' => 59 ,
1895
+ );
1896
+
1897
+ // Concatenate and throw a notice for each invalid value.
1898
+ foreach ( $ min_max_checks as $ key => $ check ) {
1899
+ if ( ! array_key_exists ( $ key , $ value ) ) {
1900
+ continue ;
1901
+ }
1902
+
1903
+ // Throw a notice for each failing value.
1904
+ foreach ( (array ) $ value [ $ key ] as $ _value ) {
1905
+ $ is_between = $ _value >= $ check ['min ' ] && $ _value <= $ check ['max ' ];
1906
+
1907
+ if ( ! is_numeric ( $ _value ) || ! $ is_between ) {
1908
+ $ error = sprintf (
1909
+ /* translators: Date query invalid date message: 1: invalid value, 2: type of value, 3: minimum valid value, 4: maximum valid value */
1910
+ __ ( 'Invalid value %1$s for %2$s. Expected value should be between %3$s and %4$s. ' ),
1911
+ esc_html ( $ _value ),
1912
+ esc_html ( $ key ),
1913
+ esc_html ( $ check ['min ' ] ),
1914
+ esc_html ( $ check ['max ' ] )
1915
+ );
1916
+
1917
+ return new WP_Error ( 'invalid-date-values ' , $ error , array ( 'status ' => 400 ) );
1918
+
1919
+ $ valid = false ;
1920
+ }
1921
+ }
1922
+ }
1923
+
1924
+ // If we already have invalid date messages, don't bother running through checkdate().
1925
+ if ( ! $ valid ) {
1926
+ return $ valid ;
1927
+ }
1928
+
1929
+ $ day_month_year_error_msg = '' ;
1930
+
1931
+ $ day_exists = array_key_exists ( 'day ' , $ value ) && is_numeric ( $ value ['day ' ] );
1932
+ $ month_exists = array_key_exists ( 'month ' , $ value ) && is_numeric ( $ value ['month ' ] );
1933
+ $ year_exists = array_key_exists ( 'year ' , $ value ) && is_numeric ( $ value ['year ' ] );
1934
+
1935
+ if ( $ day_exists && $ month_exists && $ year_exists ) {
1936
+ // 1. Checking day, month, year combination.
1937
+ if ( ! wp_checkdate ( $ value ['month ' ], $ value ['day ' ], $ value ['year ' ], sprintf ( '%s-%s-%s ' , $ value ['year ' ], $ value ['month ' ], $ value ['day ' ] ) ) ) {
1938
+ /* translators: 1: year, 2: month, 3: day of month */
1939
+ $ day_month_year_error_msg = sprintf (
1940
+ __ ( 'The following values do not describe a valid date: year %1$s, month %2$s, day %3$s. ' ),
1941
+ esc_html ( $ value ['year ' ] ),
1942
+ esc_html ( $ value ['month ' ] ),
1943
+ esc_html ( $ value ['day ' ] )
1944
+ );
1945
+
1946
+ $ valid = false ;
1947
+ }
1948
+ } elseif ( $ day_exists && $ month_exists ) {
1949
+ /*
1950
+ * 2. checking day, month combination
1951
+ * We use 2012 because, as a leap year, it's the most permissive.
1952
+ */
1953
+ if ( ! wp_checkdate ( $ value ['month ' ], $ value ['day ' ], 2012 , sprintf ( '2012-%s-%s ' , $ value ['month ' ], $ value ['day ' ] ) ) ) {
1954
+ /* translators: 1: month, 2: day of month */
1955
+ $ day_month_year_error_msg = sprintf (
1956
+ __ ( 'The following values do not describe a valid date: month %1$s, day %2$s. ' ),
1957
+ esc_html ( $ value ['month ' ] ),
1958
+ esc_html ( $ value ['day ' ] )
1959
+ );
1960
+
1961
+ $ valid = false ;
1962
+ }
1963
+ }
1964
+
1965
+ if ( ! empty ( $ day_month_year_error_msg ) ) {
1966
+ return new WP_Error ( 'invalid-date ' , $ day_month_year_error_msg , array ( 'status ' , 400 ) );
1967
+ }
1968
+ }
1969
+ return $ valid ;
1970
+ }
1766
1971
}
0 commit comments