diff --git a/admin/admin.php b/admin/admin.php index feee61b..dbeb606 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -198,8 +198,7 @@ public function handle_hidden_page_deletion( $post_id ) { if ( $exclude ) { // post was hidden // get children - $children_query = $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d", $post_id ); - $children = $wpdb->get_results( $children_query ); + $children = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d", $post_id ) ); // mark each hidden foreach ( (array) $children as $child ) { @@ -232,10 +231,8 @@ public function ajax_check_hidden_page() { $post_type = get_post_type_object( $post->post_type ); // get children pages/links - $page_children_query = $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type='$post->post_type'", $post_id ); - $page_children = $wpdb->get_results( $page_children_query ); - $link_children_query = $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type='".BU_NAVIGATION_LINK_POST_TYPE."'", $post_id ); - $link_children = $wpdb->get_results( $link_children_query ); + $page_children = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $post_id, $post->post_type ) ); + $link_children = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $post_id, BU_NAVIGATION_LINK_POST_TYPE ) ); // case no children, output the "ignore" flag if ( count( $page_children ) == 0 && count( $link_children ) == 0 ) { diff --git a/admin/manager.php b/admin/manager.php index a86db1f..298da23 100644 --- a/admin/manager.php +++ b/admin/manager.php @@ -220,7 +220,8 @@ public function load() { } } - wp_redirect( $url ); + wp_safe_redirect( $url ); + exit; } diff --git a/extras/bu-navigation-exclude.php b/extras/bu-navigation-exclude.php index aabddb0..7fdb61a 100644 --- a/extras/bu-navigation-exclude.php +++ b/extras/bu-navigation-exclude.php @@ -24,12 +24,12 @@ function bu_navigation_filter_pages_exclude( $pages ) { // Fetch pages that have been explicitly excluded from navigation lists $ids = array_keys( $pages ); - $query = sprintf( "SELECT post_id, meta_value FROM %s WHERE meta_key = '%s' AND post_id IN (%s)", - $wpdb->postmeta, - BU_NAV_META_PAGE_EXCLUDE, - implode( ',', $ids ) - ); - $exclude_meta = $wpdb->get_results( $query, OBJECT_K ); + + // Prepare statement split to accomodate the `$ids` array, as the method only accepts one extra param if the type is array. + $query = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = %s", BU_NAV_META_PAGE_EXCLUDE ); + $query .= $wpdb->prepare( " AND post_id IN (" . substr( str_repeat( ',%d', count( $ids ) ), 1 ) . ")", $ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + $exclude_meta = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( false === $exclude_meta ) { $this->plugin->log( '%s - Error querying navigation exclusions: %s', __METHOD__, $wpdb->last_error ); diff --git a/extras/bu-navigation-external-links.php b/extras/bu-navigation-external-links.php index b525d11..ae1a63b 100644 --- a/extras/bu-navigation-external-links.php +++ b/extras/bu-navigation-external-links.php @@ -74,12 +74,12 @@ function bu_navigation_filter_pages_external_links( $pages ) { if ( is_array( $pages ) && count( $pages ) > 0 ) { $ids = array_keys($pages); - $query = sprintf("SELECT post_id, meta_value FROM %s WHERE meta_key = '%s' AND post_id IN (%s)", - $wpdb->postmeta, - BU_NAV_META_TARGET, - implode( ',', $ids ) - ); - $targets = $wpdb->get_results( $query, OBJECT_K ); + + // Prepare statement split to accomodate the `$ids` array, as the method only accepts one extra param if the type is array. + $query = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = %s", BU_NAV_META_TARGET ); + $query .= $wpdb->prepare( " AND post_id IN (" . substr( str_repeat( ',%d', count( $ids ) ), 1 ) . ")", $ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + $targets = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared foreach ( $pages as $page ) { if ( $page->post_type == BU_NAVIGATION_LINK_POST_TYPE ) { diff --git a/extras/bu-navigation-labels.php b/extras/bu-navigation-labels.php index 755dbe7..5efc5ac 100644 --- a/extras/bu-navigation-labels.php +++ b/extras/bu-navigation-labels.php @@ -16,12 +16,12 @@ function bu_navigation_filter_pages_navlabels( $pages ) { if ( is_array( $pages ) && count( $pages ) > 0 ) { $ids = array_keys( $pages ); - $query = sprintf( "SELECT post_id, meta_value FROM %s WHERE meta_key = '%s' AND post_id IN (%s) AND meta_value != ''", - $wpdb->postmeta, - BU_NAV_META_PAGE_LABEL, - implode( ',', $ids ) - ); - $labels = $wpdb->get_results( $query, OBJECT_K ); + + // Prepare statement split to accomodate the `$ids` array, as the method only accepts one extra param if the type is array. + $query = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = %s", BU_NAV_META_PAGE_LABEL ); + $query = $wpdb->prepare( " AND post_id IN (" . substr( str_repeat( ',%d', count( $ids ) ), 1 ) . ") AND meta_value != ''", $ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + $labels = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( is_array( $labels ) && count( $labels ) > 0 ) { foreach ( $pages as $page ) { diff --git a/includes/class-reorder.php b/includes/class-reorder.php index e5c5b75..17e9cf4 100644 --- a/includes/class-reorder.php +++ b/includes/class-reorder.php @@ -113,8 +113,7 @@ public function run() { // Only update if menu order has actually changed if( $child->menu_order != $position ) { - $stmt = $wpdb->prepare('UPDATE ' . $wpdb->posts . ' SET menu_order = %d WHERE ID = %d', $position, $child->ID ); - $rc = $wpdb->query($stmt); + $rc = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = %d WHERE ID = %d", $position, $child->ID ) ); if( false === $rc ) { $error_msg = sprintf('Error updating menu order (%s) for post (%s): %s', $position, $child->post_title, $wpdb->last_error ); diff --git a/includes/class-tree-view.php b/includes/class-tree-view.php index 6e77194..b97e93c 100644 --- a/includes/class-tree-view.php +++ b/includes/class-tree-view.php @@ -477,12 +477,12 @@ public function filter_posts( $posts ) { // Fetch posts that have been explicitly excluded from navigation lists $ids = array_keys( $posts ); - $query = sprintf( "SELECT post_id, meta_value FROM %s WHERE meta_key = '%s' AND post_id IN (%s)", - $wpdb->postmeta, - BU_NAV_META_PAGE_EXCLUDE, - implode( ',', $ids ) - ); - $exclude_meta = $wpdb->get_results( $query, OBJECT_K ); + + // Prepare statement split to accomodate the `$ids` array, as the method only accepts one extra param if the type is array. + $query = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = %s", BU_NAV_META_PAGE_EXCLUDE ); + $query .= $wpdb->prepare( " AND post_id IN (" . substr( str_repeat( ',%d', count( $ids ) ), 1 ) . ")", $ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + $exclude_meta = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( false === $exclude_meta ) { $this->plugin->log( '%s - Error querying navigation exclusions: %s', __METHOD__, $wpdb->last_error ); diff --git a/includes/library.php b/includes/library.php index 991cb85..ccc75bf 100644 --- a/includes/library.php +++ b/includes/library.php @@ -56,7 +56,6 @@ function bu_navigation_load_sections( $post_types = array(), $include_links = tr unset( $post_types[ $index ] ); } } - $in_post_types = implode( "','", $post_types ); // Try the cache first @@ -73,14 +72,10 @@ function bu_navigation_load_sections( $post_types = array(), $include_links = tr return $all_sections; } - $wpdb->query('SET SESSION group_concat_max_len = ' . GROUP_CONCAT_MAX_LEN); - $query = sprintf(" - SELECT DISTINCT(post_parent) AS section, GROUP_CONCAT(ID) AS children - FROM %s - WHERE post_type IN ('$in_post_types') - GROUP BY post_parent - ORDER BY post_parent ASC", $wpdb->posts); - $rows = $wpdb->get_results($query); + $wpdb->query( $wpdb->prepare( "SET SESSION group_concat_max_len = %d", GROUP_CONCAT_MAX_LEN ) ); + $rows = $wpdb->get_results( + $wpdb->prepare( "SELECT DISTINCT(post_parent) AS section, GROUP_CONCAT(ID) AS children FROM $wpdb->posts WHERE post_type IN (" . substr( str_repeat( ',%s', count( $post_types ) ), 1 ) . ") GROUP BY post_parent ORDER BY post_parent ASC", $post_types ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + ); $sections = array(); $pages = array(); @@ -429,7 +424,7 @@ function bu_navigation_get_posts( $args = '' ) { $r = wp_parse_args( $args, $defaults ); // Start building the query - $where = $orderby = ''; + $where = ''; // Post fields to return $fields = array( @@ -446,7 +441,7 @@ function bu_navigation_get_posts( $args = '' ) { 'post_password' ); $fields = apply_filters( 'bu_navigation_filter_fields', $fields ); - $fields = implode( ",", $fields ); + $fields = implode( ",", esc_sql( $fields ) ); // Append post types $post_types = $r['post_types']; @@ -469,8 +464,7 @@ function bu_navigation_get_posts( $args = '' ) { } } - $post_types = implode( "','", $post_types ); - $where .= " AND post_type IN ('$post_types')"; + $where .= $wpdb->prepare( " AND post_type IN (" . substr( str_repeat( ',%s', count( $post_types ) ), 1 ) . ")", $post_types ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } // Append post statuses @@ -480,32 +474,28 @@ function bu_navigation_get_posts( $args = '' ) { $post_status = explode( ',', $post_status ); $post_status = (array) $post_status; - $post_status = implode( "','", array_map( 'trim', $post_status ) ); - $where .= " AND post_status IN ('$post_status')"; + $post_status = array_map( 'trim', $post_status ); + + $where .= $wpdb->prepare( " AND post_status IN (" . substr( str_repeat( ',%s', count( $post_status ) ), 1 ) . ")", $post_status ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } // Limit result set to posts in specific sections if ( is_array( $r['sections'] ) && ( count( $r['sections'] ) > 0 ) ) { $sections = array_map( 'absint', $r['sections'] ); - $sections = implode( ',', array_unique( $sections ) ); - $where .= " AND post_parent IN ($sections)"; + $sections = array_unique( $sections ); + $where .= $wpdb->prepare( " AND post_parent IN (" . substr( str_repeat( ',%d', count( $sections ) ), 1 ) . ")", $sections ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } // Limit to specific posts if ( is_array( $r['post__in'] ) && ( count( $r['post__in'] ) > 0 ) ) { $post__in = array_map( 'absint', $r['post__in'] ); - $post__in = implode( ',', array_unique( $post__in ) ); - $where .= " AND ID IN($post__in)"; + $post__in = array_unique( $post__in ); + $where .= $wpdb->prepare( " AND ID IN(" . substr( str_repeat( ',%d', count( $post__in ) ), 1 ) . ")", $post__in ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } - // Result sorting - $orderby = 'ORDER BY post_parent ASC, menu_order ASC'; - // Execute query, fetch results as objects in an array keyed on posts.ID - $posts = $wpdb->get_results( - "SELECT $fields FROM $wpdb->posts WHERE 1=1 $where $orderby", - OBJECT_K - ); + $posts = $wpdb->get_results( "SELECT $fields FROM $wpdb->posts WHERE 1=1 $where ORDER BY post_parent ASC, menu_order ASC", OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + if ( ! is_array( $posts ) || ( count( $posts ) == 0 ) ) return false; diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..d553d78 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,333 @@ + + + Apply WordPress Coding Standards to all Core files + + + + + + + + + + + + ./ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node_modules/* + vendor/* + + + + + + diff --git a/tests/phpunit/test-library.php b/tests/phpunit/test-library.php index 9d23b9e..ed75699 100644 --- a/tests/phpunit/test-library.php +++ b/tests/phpunit/test-library.php @@ -666,23 +666,23 @@ public function test_bu_navigation_get_pages() { // Create and order three pages using 'order' as a custom post type $cpt_args = array( 'hierarchical' => true ); - register_post_type( 'order', $cpt_args ); + register_post_type( 'test_order', $cpt_args ); // Create pages using the 'order' post type - $page_args = array( 'post_type' => 'order' , 'menu_order' => '2' ); + $page_args = array( 'post_type' => 'test_order' , 'menu_order' => '2' ); $last_order = $this->factory->post->create( $page_args ); - $page_args = array( 'post_type' => 'order' , 'menu_order' => '1' ); + $page_args = array( 'post_type' => 'test_order' , 'menu_order' => '1' ); $middle_order = $this->factory->post->create( $page_args ); - $page_args = array( 'post_type' => 'order' , 'menu_order' => '0' ); + $page_args = array( 'post_type' => 'test_order' , 'menu_order' => '0' ); $first_order = $this->factory->post->create( $page_args ); // Construct Expected Order $expected_order = array( $first_order, $middle_order, $last_order ); // Get Pages - $args = array( 'post_types' => array( 'order' )); + $args = array( 'post_types' => array( 'test_order' )); $pages = bu_navigation_get_pages( $args ); // Get actual page order