WordPress.org

Make WordPress Core

Ticket #18081: transform_array_to_sql_condition.diff

File transform_array_to_sql_condition.diff, 9.6 KB (added by tott, 4 years ago)

Implementing transform_array_to_sql_condition() in taxonomy.php

Line 
1Index: wp-includes/taxonomy.php
2===================================================================
3--- wp-includes/taxonomy.php    (revision 17409)
4+++ wp-includes/taxonomy.php    (working copy)
5@@ -%ld,%ld +%ld,%ld @@
6 
7        $order = ( 'desc' == strtolower( $order ) ) ? 'DESC' : 'ASC';
8 
9-       $term_ids = array_map('intval', $term_ids );
10+       $taxonomies_add = transform_array_to_sql_condition( $taxonomies );
11+       $term_ids_add = transform_array_to_sql_condition( $term_ids, true );
12 
13-       $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
14-       $term_ids = "'" . implode( "', '", $term_ids ) . "'";
15+       $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy $taxonomies_add AND tt.term_id $term_ids_add ORDER BY tr.object_id $order");
16 
17-       $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order");
18-
19        if ( ! $object_ids )
20                return array();
21 
22@@ -%ld,%ld +%ld,%ld @@
23                                if ( empty( $terms ) )
24                                        continue;
25 
26-                               $terms = implode( ',', $terms );
27-
28+                               $terms_add = transform_array_to_sql_condition( $terms, true );
29+                               
30                                $where[] = "$primary_table.$primary_id_column NOT IN (
31                                        SELECT object_id
32                                        FROM $wpdb->term_relationships
33-                                       WHERE term_taxonomy_id IN ($terms)
34+                                       WHERE term_taxonomy_id $terms_add
35                                )";
36                        } elseif ( 'AND' == $operator ) {
37 
38@@ -%ld,%ld +%ld,%ld @@
39 
40                                $num_terms = count( $terms );
41 
42-                               $terms = implode( ',', $terms );
43+                               $terms_add = transform_array_to_sql_condition( $terms, true );
44 
45                                $where[] = "$primary_table.$primary_id_column IN (
46                                        SELECT object_id
47                                        FROM $wpdb->term_relationships
48-                                       WHERE term_taxonomy_id IN ($terms)
49+                                       WHERE term_taxonomy_id $terms_add
50                                        GROUP BY object_id HAVING COUNT(object_id) = $num_terms
51                                )";
52                        }
53@@ -%ld,%ld +%ld,%ld @@
54                switch ( $field ) {
55                        case 'slug':
56                        case 'name':
57-                               $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $terms ) ) . "'";
58+                               $terms_add = transform_array_to_sql_condition( $terms, false, 'sanitize_title_for_query' );
59                                $terms = $wpdb->get_col( "
60                                        SELECT $wpdb->term_taxonomy.$resulting_field
61                                        FROM $wpdb->term_taxonomy
62                                        INNER JOIN $wpdb->terms USING (term_id)
63                                        WHERE taxonomy = '$taxonomy'
64-                                       AND $wpdb->terms.$field IN ($terms)
65+                                       AND $wpdb->terms.$field $terms_add
66                                " );
67                                break;
68 
69                        default:
70-                               $terms = implode( ',', array_map( 'intval', $terms ) );
71+                               $terms_add = transform_array_to_sql_condition( $terms, true );
72                                $terms = $wpdb->get_col( "
73                                        SELECT $resulting_field
74                                        FROM $wpdb->term_taxonomy
75                                        WHERE taxonomy = '$taxonomy'
76-                                       AND term_id IN ($terms)
77+                                       AND term_id $terms_add
78                                " );
79                }
80        }
81@@ -%ld,%ld +%ld,%ld @@
82        else
83                $order = '';
84 
85-       $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')";
86+       $taxonomies_add = transform_array_to_sql_condition( $taxonomies );
87+
88+       $where = "tt.taxonomy $taxonomies_add";
89        $inclusions = '';
90        if ( !empty($include) ) {
91                $exclude = '';
92@@ -%ld,%ld +%ld,%ld @@
93 
94        foreach ( (array) $taxonomies as $taxonomy ) {
95                $tt_ids = wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids'));
96-               $in_tt_ids = "'" . implode("', '", $tt_ids) . "'";
97+               $in_tt_ids = transform_array_to_sql_condition( $tt_ids, true );
98+
99                do_action( 'delete_term_relationships', $object_id, $tt_ids );
100-               $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id) );
101+               $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id $in_tt_ids", $object_id) );
102                do_action( 'deleted_term_relationships', $object_id, $tt_ids );
103                wp_update_term_count($tt_ids, $taxonomy);
104        }
105@@ -%ld,%ld +%ld,%ld @@
106        if ( !empty($orderby) )
107                $orderby = "ORDER BY $orderby";
108 
109-       $taxonomies = "'" . implode("', '", $taxonomies) . "'";
110-       $object_ids = implode(', ', $object_ids);
111-
112+       $taxonomies_add = transform_array_to_sql_condition( $taxonomies );
113+       $object_ids_add = transform_array_to_sql_condition( $object_ids, true );
114+       $object_ids = implode( ", ", $object_ids ); // left for compatibility reasons. it's used in filter below
115+       
116        $select_this = '';
117        if ( 'all' == $fields )
118                $select_this = 't.*, tt.*';
119@@ -%ld,%ld +%ld,%ld @@
120        else if ( 'all_with_object_id' == $fields )
121                $select_this = 't.*, tt.*, tr.object_id';
122 
123-       $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tr.object_id IN ($object_ids) $orderby $order";
124+       $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy $taxonomies_add AND tr.object_id $object_ids_add $orderby $order";
125 
126        if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
127                $terms = array_merge($terms, $wpdb->get_results($query));
128@@ -%ld,%ld +%ld,%ld @@
129        } else if ( 'ids' == $fields || 'names' == $fields ) {
130                $terms = array_merge($terms, $wpdb->get_col($query));
131        } else if ( 'tt_ids' == $fields ) {
132-               $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order");
133+               $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id $object_ids_add AND tt.taxonomy $taxonomies_add $orderby $order");
134        }
135 
136        if ( ! $terms )
137@@ -%ld,%ld +%ld,%ld @@
138        if ( ! $append ) {
139                $delete_terms = array_diff($old_tt_ids, $tt_ids);
140                if ( $delete_terms ) {
141-                       $in_delete_terms = "'" . implode("', '", $delete_terms) . "'";
142+                       $in_delete_terms = transform_array_to_sql_condition( $delete_terms, true );
143                        do_action( 'delete_term_relationships', $object_id, $delete_terms );
144-                       $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_delete_terms)", $object_id) );
145+                       $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id $in_delete_terms", $object_id) );
146                        do_action( 'deleted_term_relationships', $object_id, $delete_terms );
147                        wp_update_term_count($delete_terms, $taxonomy);
148                }
149@@ -%ld,%ld +%ld,%ld @@
150        $taxonomies = array();
151        // If no taxonomy, assume tt_ids.
152        if ( empty($taxonomy) ) {
153-               $tt_ids = array_map('intval', $ids);
154-               $tt_ids = implode(', ', $tt_ids);
155-               $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)");
156+               $tt_ids = transform_array_to_sql_condition( $tt_ids, true );
157+               $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id $tt_ids");
158                $ids = array();
159                foreach ( (array) $terms as $term ) {
160                        $taxonomies[] = $term->taxonomy;
161@@ -%ld,%ld +%ld,%ld @@
162        // Get the object and term ids and stick them in a lookup table
163        $tax_obj = get_taxonomy($taxonomy);
164        $object_types = esc_sql($tax_obj->object_type);
165-       $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'");
166+       $term_ids_in = transform_array_to_sql_condition( array_keys( $term_ids ), true );
167+       
168+       $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id $term_ids_in AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'");
169        foreach ( $results as $row ) {
170                $id = $term_ids[$row->term_taxonomy_id];
171                $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
172@@ -%ld,%ld +%ld,%ld @@
173 
174        return $parent;
175 }
176+
177+/**
178+ * Given an array of values this function will return a string to be put in
179+ * a sql query based on the amount of values. for multiple values it will return "IN ('val1', 'val2'..)"
180+ * while for single values it will return "= 'val1'" in order to avoid the creation of temporary
181+ * tables and improve performance
182+ *
183+ * @param array $values
184+ * @param bool $treat_as_integer would make sure to skip "'" escaping and cast all values as integers
185+ * @param mixed $array_map_sanitation a function name or callback to be used to sanitize $values via array_map() before usage
186+ * @return string
187+ */
188+function transform_array_to_sql_condition( $values, $treat_as_integer = false, $array_map_sanitation = NULL ) {
189+       $values = (array) $values;
190+       if ( !is_null( $array_map_sanitation ) )
191+               $values = array_map( $array_map_sanitation, $values );
192+               
193+       if ( true === $treat_as_integer ) {
194+               $glue = ", ";
195+               $pre_glue = $post_glue = "";
196+               $values = array_map( 'intval', $values );
197+       } else {
198+               $glue = "',' ";
199+               $pre_glue = $post_glue = "'";
200+       }
201+       if ( count( $values ) > 1 ) {
202+               $vals = $pre_glue . implode( $glue, $values ) . $post_glue;
203+               $vals_sql_add = "IN ($vals)";
204+       } else {
205+               $vals_sql_add = "= '" . array_shift( $values ) . "'";
206+       }
207+       return $vals_sql_add;
208+}
209\ No newline at end of file