| @@ -112,8 +112,22 @@ | ||
| 112 | 112 | '/get_table_of_contents/', |
| 113 | 113 | array( |
| 114 | 114 | 'methods' => WP_REST_Server::READABLE, |
| 115 | 115 | 'callback' => array( $this, 'get_table_of_contents' ), |
| 116 | + 'args' => array( | |
| 117 | + 'headings' => array( | |
| 118 | + 'default' => array(), | |
| 119 | + 'sanitize_callback' => array( $this, 'sanitize_toc_headings' ), | |
| 120 | + ), | |
| 121 | + 'allowedHeaders' => array( | |
| 122 | + 'default' => array(), | |
| 123 | + 'sanitize_callback' => array( $this, 'sanitize_toc_allowed_headers' ), | |
| 124 | + ), | |
| 125 | + 'listStyle' => array( | |
| 126 | + 'default' => 'ol', | |
| 127 | + 'sanitize_callback' => array( $this, 'sanitize_toc_list_style' ), | |
| 128 | + ), | |
| 129 | + ), | |
| 116 | 130 | 'permission_callback' => '__return_true', |
| 117 | 131 | ) |
| 118 | 132 | ); |
| 119 | 133 | |
| @@ -1268,8 +1282,80 @@ | ||
| 1268 | 1282 | ); |
| 1269 | 1283 | } |
| 1270 | 1284 | |
| 1271 | 1285 | /** |
| 1286 | + * Sanitize TOC headings list. | |
| 1287 | + * | |
| 1288 | + * @param mixed $headings request headings. | |
| 1289 | + * @return array | |
| 1290 | + */ | |
| 1291 | + public function sanitize_toc_headings( $headings ) { | |
| 1292 | + if ( ! is_array( $headings ) ) { | |
| 1293 | + return array(); | |
| 1294 | + } | |
| 1295 | + | |
| 1296 | + $sanitized = array(); | |
| 1297 | + | |
| 1298 | + foreach ( $headings as $heading ) { | |
| 1299 | + if ( ! is_array( $heading ) ) { | |
| 1300 | + continue; | |
| 1301 | + } | |
| 1302 | + | |
| 1303 | + $level = isset( $heading['level'] ) ? absint( $heading['level'] ) : 0; | |
| 1304 | + | |
| 1305 | + if ( $level < 1 || $level > 6 ) { | |
| 1306 | + continue; | |
| 1307 | + } | |
| 1308 | + | |
| 1309 | + $sanitized[] = array( | |
| 1310 | + 'level' => $level, | |
| 1311 | + 'content' => isset( $heading['content'] ) ? wp_kses_post( $heading['content'] ) : '', | |
| 1312 | + 'anchor' => isset( $heading['anchor'] ) ? sanitize_text_field( $heading['anchor'] ) : '', | |
| 1313 | + ); | |
| 1314 | + } | |
| 1315 | + | |
| 1316 | + return $sanitized; | |
| 1317 | + } | |
| 1318 | + | |
| 1319 | + /** | |
| 1320 | + * Sanitize TOC allowed headers list. | |
| 1321 | + * | |
| 1322 | + * @param mixed $allowed_headers request allowed headers. | |
| 1323 | + * @return array | |
| 1324 | + */ | |
| 1325 | + public function sanitize_toc_allowed_headers( $allowed_headers ) { | |
| 1326 | + if ( ! is_array( $allowed_headers ) ) { | |
| 1327 | + return array(); | |
| 1328 | + } | |
| 1329 | + | |
| 1330 | + $sanitized = array_values( | |
| 1331 | + array_unique( | |
| 1332 | + array_filter( | |
| 1333 | + array_map( 'absint', $allowed_headers ), | |
| 1334 | + static function ( $level ) { | |
| 1335 | + return $level >= 1 && $level <= 6; | |
| 1336 | + } | |
| 1337 | + ) | |
| 1338 | + ) | |
| 1339 | + ); | |
| 1340 | + | |
| 1341 | + return $sanitized; | |
| 1342 | + } | |
| 1343 | + | |
| 1344 | + /** | |
| 1345 | + * Sanitize TOC list style. | |
| 1346 | + * | |
| 1347 | + * @param mixed $list_style request list style. | |
| 1348 | + * @return string | |
| 1349 | + */ | |
| 1350 | + public function sanitize_toc_list_style( $list_style ) { | |
| 1351 | + $list_style = is_string( $list_style ) ? sanitize_text_field( $list_style ) : 'ol'; | |
| 1352 | + $allowed = array( 'ol', 'ul', 'ol-styled', 'ul-styled' ); | |
| 1353 | + | |
| 1354 | + return in_array( $list_style, $allowed, true ) ? $list_style : 'ol'; | |
| 1355 | + } | |
| 1356 | + | |
| 1357 | + /** | |
| 1272 | 1358 | * Get TOC. |
| 1273 | 1359 | * |
| 1274 | 1360 | * @param WP_REST_Request $request request object. |
| 1275 | 1361 | * |
| @@ -1277,19 +1363,16 @@ | ||
| 1277 | 1363 | */ |
| 1278 | 1364 | public function get_table_of_contents( WP_REST_Request $request ) { |
| 1279 | 1365 | $headings = $request->get_param( 'headings' ); |
| 1280 | 1366 | $allowed_headers = $request->get_param( 'allowedHeaders' ); |
| 1281 | - $list_style = $request->get_param( 'listStyle' ) ? $request->get_param( 'listStyle' ) : 'ol'; | |
| 1367 | + $list_style = $request->get_param( 'listStyle' ); | |
| 1282 | 1368 | |
| 1283 | 1369 | $html = ''; |
| 1284 | 1370 | |
| 1285 | - if ( ! $allowed_headers || empty( $allowed_headers ) ) { | |
| 1371 | + if ( empty( $allowed_headers ) || empty( $headings ) ) { | |
| 1286 | 1372 | return $this->success( $html ); |
| 1287 | 1373 | } |
| 1288 | 1374 | |
| 1289 | - // covert string values to int. | |
| 1290 | - $allowed_headers = array_map( 'intval', $allowed_headers ); | |
| 1291 | - | |
| 1292 | 1375 | $current_depth = 6; |
| 1293 | 1376 | $numbered_items = array(); |
| 1294 | 1377 | $numbered_items_min = null; |
| 1295 | 1378 | $count = count( $headings ); |
| @@ -1302,9 +1385,9 @@ | ||
| 1302 | 1385 | } |
| 1303 | 1386 | |
| 1304 | 1387 | $numbered_items[ $current_depth ] = 0; |
| 1305 | 1388 | $numbered_items_min = $current_depth; |
| 1306 | - for ( $i = 0; $i < $count; $i ++ ) { | |
| 1389 | + for ( $i = 0; $i < $count; $i++ ) { | |
| 1307 | 1390 | if ( $current_depth === (int) $headings[ $i ]['level'] ) { |
| 1308 | 1391 | $html .= '<li>'; |
| 1309 | 1392 | } |
| 1310 | 1393 | |