-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadmin-search-meta.php
228 lines (195 loc) · 8.04 KB
/
admin-search-meta.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
<?php
/*
Plugin Name: Admin Search Meta
Plugin URI: https://github.com/rmpel/admin-search-meta
Version: 0.0.3
Author: Remon Pel
Description: Allow filtering your posts-panels by meta. Not to be confused with Admin Meta Search, which did a small portion of what this plugin does, and is defunct for over 6 years.
Requires PHP: 5.6.0
Requires at least: 4.0
Textdomain: rmp_asm
*/
namespace RemonPel\Tools;
class AdminSearchMeta {
public static function getInstance() {
static $instance;
if ( ! $instance ) {
$instance = new static();
}
return $instance;
}
public function __construct() {
global $pagenow;
add_action('plugins_loaded', function () {
load_plugin_textdomain( 'rmp_asm', false, plugin_basename(dirname(__FILE__)) . '/pomo' );
});
if ( is_admin() && $pagenow == 'edit.php' && isset( $_GET['post_type'] ) && ! empty( $_GET['s'] ) ) {
add_filter( 'posts_join', function ( $join ) {
return call_user_func( [ static::class, 'getInstance' ] )->posts_join( $join );
} );
add_filter( 'posts_where', function ( $where ) {
return call_user_func( [ static::class, 'getInstance' ] )->posts_where( $where );
} );
add_filter( 'posts_distinct', function ( $distinct ) {
return call_user_func( [ static::class, 'getInstance' ] )->posts_distinct( $distinct );
} );
}
add_action( 'admin_menu', function () {
add_menu_page( __( 'Admin Meta Search', 'rmp_asm' ), __( 'Admin Meta Search', 'rmp_asm' ), 'manage_options', 'rmp_asm', [
static::class,
'admin_page_callback'
] );
} );
}
private function alterations() {
$alters = get_option( 'admin_search_meta_options', [] );
$data = isset( $alters[ $_GET['post_type'] ] ) ? $alters[ $_GET['post_type'] ] : false;
if ( $data && $data['enabled'] ) {
return ! empty( $data['fields'] ) ? $data['fields'] : true;
}
return false;
}
/**
* Join postmeta in admin post search
*
* @return string SQL join
*/
private function posts_distinct( $distinct ) {
global $wpdb;
$alterations = static::alterations();
if ( $alterations ) {
return 'DISTINCT';
}
return $distinct;
}
/**
* Join postmeta in admin post search
*
* @return string SQL join
*/
private function posts_join( $join ) {
global $wpdb;
$alterations = static::alterations();
if ( $alterations ) {
$join .= 'LEFT JOIN ' . $wpdb->postmeta . ' post_meta_admin_search ON ' . $wpdb->posts . '.ID = post_meta_admin_search.post_id ';
}
return $join;
}
/**
* Filtering the where clause in admin post search query
*
* I have considered creating separate joins for each selected meta_key, but it is also possible to do a global meta-match, so there would be no named
* meta_key-join and we would need to do a SELECT DISTINCT anyways, so the solution is in fact to do a SELECT DISTINCT as it works in all cases.
*
* @return string SQL WHERE
*/
private function posts_where( $where ) {
global $wpdb;
$alterations = static::alterations();
if ( $alterations ) {
if ( is_bool( $alterations ) ) {
$sql_alterations = '';
} else {
$alterations = implode( "', '", array_map( 'esc_sql', $alterations ) );
if ( ! $alterations ) {
//misconfiguration, just assume "all"
$sql_alterations = '';
} else {
$sql_alterations = " post_meta_admin_search.meta_key IN ('$alterations') AND ";
}
}
$where = preg_replace(
"/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"(" . $wpdb->posts . ".post_title LIKE $1) OR ( $sql_alterations post_meta_admin_search.meta_value LIKE $1 )", $where );
}
return $where;
}
// admin panel
public static function admin_page_callback() {
global $wpdb;
$post_types = get_post_types( [ 'public' => 1 ], 'objects' );
unset($post_types['attachment']);
$settings = get_option( 'admin_search_meta_options', [] );
$settings = $settings ?: [];
$meta_fields = array_combine(array_keys($post_types), array_fill(0, count($post_types), []));
$sql_post_types = implode( "', '", array_map( 'esc_sql', array_keys($post_types) ) );
$fields = $wpdb->get_results( sprintf( "SELECT DISTINCT(m.meta_key), p.post_type FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} m ON m.post_id = p.ID WHERE p.post_type IN ('%s')", $sql_post_types ) );
foreach ( $fields as $field ) {
$meta_fields[ $field->post_type ][] = $field->meta_key;
}
array_walk( $meta_fields, function ( &$fields ) {
natcasesort( $fields );
} );
if ( isset( $_POST ) && isset( $_POST['settings'] ) ) {
$new_settings = $_POST['settings'];
array_walk( $new_settings, function ( &$setting ) {
$setting['fields'] = array_filter( (array) $setting['fields'] );
} );
$new_settings = array_filter( $new_settings );
update_option( 'admin_search_meta_options', $new_settings );
print '<script>document.location=' . json_encode( remove_query_arg( '_' ) ) . ';</script>';
exit;
}
?>
<div class="wrap">
<h2><?php _e( 'Admin Meta Search', 'rmp_asm' ); ?></h2>
<p><?php _e( 'Select post-types for which you want to allow meta-searching in WP-Admin.', 'rmp_asm' ); ?></p>
<form action="<?php print esc_attr( add_query_arg( [ '_' => microtime( true ) ] ) ); ?>" method="post">
<?php foreach ( $meta_fields as $post_type => $fields ) { ?>
<div class="set-wrap">
<input id="post-type-<?php print $post_type; ?>"
type="checkbox" <?php if ( isset($settings[ $post_type ]) && $settings[ $post_type ]['enabled'] ) { print 'checked="checked"'; } ?>
value="<?php print $post_type; ?>" name="settings[<?php print $post_type; ?>][enabled]"/>
<label for="post-type-<?php print $post_type; ?>"><?php print $post_types[ $post_type ]->label; ?></label>
<fieldset id="fields-for-<?php print $post_type; ?>">
<p><?php _e( 'If none selected, all meta will be searched.', 'rmp_asm' ); ?></p>
<p><?php if (!$fields) { print sprintf( __( 'There are no posts of type %s yet to determine available meta-keys.', 'rmp_asm' ), $post_types[ $post_type ]->label); } ?></p>
<div class="flex">
<?php foreach ( $fields as $field ) {
$sane_key = 'f' . md5( $post_type . '-' . $field ); ?>
<div class="item-wrap">
<input id="<?php print $sane_key; ?>"
type="checkbox" <?php if ( isset($settings[ $post_type ]['fields'][ $field ] ) ) { print 'checked="checked"'; } ?>
value="<?php print $field; ?>"
name="settings[<?php print $post_type; ?>][fields][<?php print $field; ?>]"/>
<label for="<?php print $sane_key; ?>"><?php print $field; ?></label>
</div>
<?php } ?>
</div>
</fieldset>
</div>
<?php } ?>
<button class="button button-primary button-large"><?php _e( 'Save', 'rmp_asm' ); ?></button>
</form>
</div>
<style>
input[type=checkbox]:checked + label + fieldset {
display: block;
}
fieldset {
display: none;
border: 1px solid grey;
padding: 2px
}
fieldset .flex {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: stretch;
align-content: flex-start;
}
fieldset .flex:after {
content: '';
flex: auto
}
fieldset .item-wrap {
display: inline-block;
width: 20%;
min-width: 250px;
}
</style>
<?php
}
}
AdminSearchMeta::getInstance();