/** * Query a set of Stream records. * * ## OPTIONS * * [--fields=<fields>] * : Limit the output to specific object fields. * * [--<field>=<value>] * : One or more args to pass to WP_Stream_Query. * * [--format=<format>] * : Accepted values: table, count, json, json_pretty, csv. Default: table * * ## AVAILABLE FIELDS TO QUERY * * You can build a query from these fields: * * * user_id * * user_id__in * * user_id__not_in * * user_role * * user_role__in * * user_role__not_in * * date * * date_from * * date_to * * date_after * * date_before * * ip * * ip__in * * ip__not_in * * connector * * connector__in * * connector__not_in * * context * * context__in * * context__not_in * * action * * action__in * * action__not_in * * search * * search_field * * record * * record__in * * record__not_in * * records_per_page * * paged * * order * * orderby * * ## AVAILABLE FIELDS * * These fields will be displayed by default for each post: * * * created * * ip * * user_id * * user_role * * summary * * These fields are optionally available: * * * ID * * site_id * * blog_id * * object_id * * connector * * context * * action * * ## EXAMPLES * * wp stream query --user_role__not_in=administrator --date_after=2015-01-01T12:00:00 * wp stream query --user_id=1 --action=login --records_per_page=50 --fields=created * * @see WP_Stream_Query * @see https://github.com/wp-stream/stream/wiki/WP-CLI-Command * @see https://github.com/wp-stream/stream/wiki/Query-Reference */ public function query($args, $assoc_args) { unset($args); $query_args = array(); $formatted_records = array(); $this->connection(); if (empty($assoc_args['fields'])) { $fields = array('created', 'ip', 'user_id', 'user_role', 'summary'); } else { $fields = explode(',', $assoc_args['fields']); } foreach ($assoc_args as $key => $value) { if ('format' === $key) { continue; } $query_args[$key] = $value; } $query_args['fields'] = implode(',', $fields); $records = wp_stream_get_instance()->db->query->query($query_args); // Make structure Formatter compatible foreach ((array) $records as $key => $record) { $formatted_records[$key] = array(); // Catch any fields missing in records foreach ($fields as $field) { if (!array_key_exists($field, $record)) { $record->{$field} = null; } } foreach ($record as $field_name => $field) { $formatted_records[$key] = array_merge($formatted_records[$key], $this->format_field($field_name, $field)); } } if (isset($assoc_args['format']) && 'table' !== $assoc_args['format']) { if ('count' === $assoc_args['format']) { WP_CLI::line(count($records)); } if ('json' === $assoc_args['format']) { WP_CLI::line(wp_stream_json_encode($formatted_records)); } if ('json_pretty' === $assoc_args['format']) { if (version_compare(PHP_VERSION, '5.4', '<')) { WP_CLI::line(wp_stream_json_encode($formatted_records)); // xss ok } else { WP_CLI::line(wp_stream_json_encode($formatted_records, JSON_PRETTY_PRINT)); // xss ok } } if ('csv' === $assoc_args['format']) { WP_CLI::line($this->csv_format($formatted_records)); } return; } $formatter = new \WP_CLI\Formatter($assoc_args, $fields); $formatter->display_items($formatted_records); }
/** * Compile HTML needed for displaying the field * * @param array $field Field settings * * @return string HTML to be displayed */ public function render_field($field) { $output = null; $type = isset($field['type']) ? $field['type'] : null; $section = isset($field['section']) ? $field['section'] : null; $name = isset($field['name']) ? $field['name'] : null; $class = isset($field['class']) ? $field['class'] : null; $placeholder = isset($field['placeholder']) ? $field['placeholder'] : null; $description = isset($field['desc']) ? $field['desc'] : null; $href = isset($field['href']) ? $field['href'] : null; $rows = isset($field['rows']) ? $field['rows'] : 10; $cols = isset($field['cols']) ? $field['cols'] : 50; $after_field = isset($field['after_field']) ? $field['after_field'] : null; $default = isset($field['default']) ? $field['default'] : null; $min = isset($field['min']) ? $field['min'] : 0; $max = isset($field['max']) ? $field['max'] : 999; $step = isset($field['step']) ? $field['step'] : 1; $title = isset($field['title']) ? $field['title'] : null; $nonce = isset($field['nonce']) ? $field['nonce'] : null; if (isset($field['value'])) { $current_value = $field['value']; } else { if (isset($this->options[$section . '_' . $name])) { $current_value = $this->options[$section . '_' . $name]; } else { $current_value = null; } } $option_key = $this->option_key; if (is_callable($current_value)) { $current_value = call_user_func($current_value); } if (!$type || !$section || !$name) { return ''; } if ('multi_checkbox' === $type && (empty($field['choices']) || !is_array($field['choices']))) { return ''; } switch ($type) { case 'text': case 'number': $output = sprintf('<input type="%1$s" name="%2$s[%3$s_%4$s]" id="%2$s_%3$s_%4$s" class="%5$s" placeholder="%6$s" min="%7$d" max="%8$d" step="%9$d" value="%10$s" /> %11$s', esc_attr($type), esc_attr($option_key), esc_attr($section), esc_attr($name), esc_attr($class), esc_attr($placeholder), esc_attr($min), esc_attr($max), esc_attr($step), esc_attr($current_value), wp_kses_post($after_field)); break; case 'textarea': $output = sprintf('<textarea name="%1$s[%2$s_%3$s]" id="%1$s_%2$s_%3$s" class="%4$s" placeholder="%5$s" rows="%6$d" cols="%7$d">%8$s</textarea> %9$s', esc_attr($option_key), esc_attr($section), esc_attr($name), esc_attr($class), esc_attr($placeholder), absint($rows), absint($cols), esc_textarea($current_value), wp_kses_post($after_field)); break; case 'checkbox': if (isset($current_value)) { $value = $current_value; } elseif (isset($default)) { $value = $default; } else { $value = 0; } $output = sprintf('<label><input type="checkbox" name="%1$s[%2$s_%3$s]" id="%1$s[%2$s_%3$s]" value="1" %4$s /> %5$s</label>', esc_attr($option_key), esc_attr($section), esc_attr($name), checked($value, 1, false), wp_kses_post($after_field)); break; case 'multi_checkbox': $output = sprintf('<div id="%1$s[%2$s_%3$s]"><fieldset>', esc_attr($option_key), esc_attr($section), esc_attr($name)); // Fallback if nothing is selected $output .= sprintf('<input type="hidden" name="%1$s[%2$s_%3$s][]" value="__placeholder__" />', esc_attr($option_key), esc_attr($section), esc_attr($name)); $current_value = (array) $current_value; $choices = $field['choices']; if (is_callable($choices)) { $choices = call_user_func($choices); } foreach ($choices as $value => $label) { $output .= sprintf('<label>%1$s <span>%2$s</span></label><br />', sprintf('<input type="checkbox" name="%1$s[%2$s_%3$s][]" value="%4$s" %5$s />', esc_attr($option_key), esc_attr($section), esc_attr($name), esc_attr($value), checked(in_array($value, $current_value), true, false)), esc_html($label)); } $output .= '</fieldset></div>'; break; case 'select': $current_value = $this->options[$section . '_' . $name]; $default_value = isset($default['value']) ? $default['value'] : '-1'; $default_name = isset($default['name']) ? $default['name'] : 'Choose Setting'; $output = sprintf('<select name="%1$s[%2$s_%3$s]" class="%1$s_%2$s_%3$s">', esc_attr($option_key), esc_attr($section), esc_attr($name)); $output .= sprintf('<option value="%1$s" %2$s>%3$s</option>', esc_attr($default_value), checked($default_value === $current_value, true, false), esc_html($default_name)); foreach ($field['choices'] as $value => $label) { $output .= sprintf('<option value="%1$s" %2$s>%3$s</option>', esc_attr($value), checked($value === $current_value, true, false), esc_html($label)); } $output .= '</select>'; break; case 'file': $output = sprintf('<input type="file" name="%1$s[%2$s_%3$s]" class="%4$s">', esc_attr($option_key), esc_attr($section), esc_attr($name), esc_attr($class)); break; case 'link': $output = sprintf('<a id="%1$s_%2$s_%3$s" class="%4$s" href="%5$s">%6$s</a>', esc_attr($option_key), esc_attr($section), esc_attr($name), esc_attr($class), esc_attr($href), esc_attr($title)); break; case 'select2': if (!isset($current_value)) { $current_value = ''; } $data_values = array(); if (isset($field['choices'])) { $choices = $field['choices']; if (is_callable($choices)) { $param = isset($field['param']) ? $field['param'] : null; $choices = call_user_func($choices, $param); } foreach ($choices as $key => $value) { if (is_array($value)) { $child_values = array(); if (isset($value['children'])) { $child_values = array(); foreach ($value['children'] as $child_key => $child_value) { $child_values[] = array('id' => $child_key, 'text' => $child_value); } } if (isset($value['label'])) { $data_values[] = array('id' => $key, 'text' => $value['label'], 'children' => $child_values); } } else { $data_values[] = array('id' => $key, 'text' => $value); } } $class .= ' with-source'; } $input_html = sprintf('<input type="hidden" name="%1$s[%2$s_%3$s]" data-values=\'%4$s\' value="%5$s" class="select2-select %6$s" data-placeholder="%7$s" />', esc_attr($option_key), esc_attr($section), esc_attr($name), esc_attr(wp_stream_json_encode($data_values)), esc_attr($current_value), esc_attr($class), sprintf(esc_html__('Any %s', 'stream'), $title)); $output = sprintf('<div class="%1$s_%2$s_%3$s">%4$s</div>', esc_attr($option_key), esc_attr($section), esc_attr($name), $input_html); break; case 'rule_list': $output = '<p class="description">' . esc_html($description) . '</p>'; $actions_top = sprintf('<input type="button" class="button" id="%1$s_new_rule" value="+ %2$s" />', esc_attr($section . '_' . $name), esc_html__('Add New Rule', 'stream')); $actions_bottom = sprintf('<input type="button" class="button" id="%1$s_remove_rules" value="%2$s" />', esc_attr($section . '_' . $name), esc_html__('Delete Selected Rules', 'stream')); $output .= sprintf('<div class="tablenav top">%1$s</div>', $actions_top); $output .= '<table class="wp-list-table widefat fixed stream-exclude-list">'; unset($description); $heading_row = sprintf('<tr> <td scope="col" class="manage-column column-cb check-column">%1$s</td> <th scope="col" class="manage-column">%2$s</th> <th scope="col" class="manage-column">%3$s</th> <th scope="col" class="manage-column">%4$s</th> <th scope="col" class="manage-column">%5$s</th> <th scope="col" class="actions-column manage-column"><span class="hidden">%6$s</span></th> </tr>', '<input class="cb-select" type="checkbox" />', esc_html__('Author or Role', 'stream'), esc_html__('Context', 'stream'), esc_html__('Action', 'stream'), esc_html__('IP Address', 'stream'), esc_html__('Filters', 'stream')); $exclude_rows = array(); // Prepend an empty row $current_value['exclude_row'] = array('helper' => '') + (isset($current_value['exclude_row']) ? $current_value['exclude_row'] : array()); foreach ($current_value['exclude_row'] as $key => $value) { // Prepare values $author_or_role = isset($current_value['author_or_role'][$key]) ? $current_value['author_or_role'][$key] : ''; $connector = isset($current_value['connector'][$key]) ? $current_value['connector'][$key] : ''; $context = isset($current_value['context'][$key]) ? $current_value['context'][$key] : ''; $action = isset($current_value['action'][$key]) ? $current_value['action'][$key] : ''; $ip_address = isset($current_value['ip_address'][$key]) ? $current_value['ip_address'][$key] : ''; // Author or Role dropdown menu $author_or_role_values = array(); $author_or_role_selected = array(); foreach ($this->get_roles() as $role_id => $role) { $args = array('id' => $role_id, 'text' => $role); $users = count_users(); $count = isset($users['avail_roles'][$role_id]) ? $users['avail_roles'][$role_id] : 0; if (!empty($count)) { $args['user_count'] = sprintf(_n('1 user', '%s users', absint($count), 'stream'), absint($count)); } if ($role_id === $author_or_role) { $author_or_role_selected['id'] = $role_id; $author_or_role_selected['text'] = $role; } $author_or_role_values[] = $args; } if (empty($author_or_role_selected) && is_numeric($author_or_role)) { $user = new WP_User($author_or_role); $display_name = 0 === $user->ID ? esc_html__('N/A', 'stream') : $user->display_name; $author_or_role_selected = array('id' => $user->ID, 'text' => $display_name); } $author_or_role_input = sprintf('<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" data-values=\'%5$s\' data-selected-id=\'%6$s\' data-selected-text=\'%7$s\' value="%6$s" class="select2-select %4$s" data-placeholder="%8$s" data-nonce="%9$s" />', esc_attr($option_key), esc_attr($section), esc_attr($name), 'author_or_role', esc_attr(wp_stream_json_encode($author_or_role_values)), isset($author_or_role_selected['id']) ? esc_attr($author_or_role_selected['id']) : '', isset($author_or_role_selected['text']) ? esc_attr($author_or_role_selected['text']) : '', esc_html__('Any Author or Role', 'stream'), esc_attr(wp_create_nonce('stream_get_users'))); // Context dropdown menu $context_values = array(); foreach ($this->get_terms_labels('context') as $context_id => $context_data) { if (is_array($context_data)) { $child_values = array(); if (isset($context_data['children'])) { $child_values = array(); foreach ($context_data['children'] as $child_id => $child_value) { $child_values[] = array('id' => $child_id, 'text' => $child_value, 'parent' => $context_id); } } if (isset($context_data['label'])) { $context_values[] = array('id' => $context_id, 'text' => $context_data['label'], 'children' => $child_values); } } else { $context_values[] = array('id' => $context_id, 'text' => $context_data); } } $connector_input = sprintf('<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" class="%4$s" value="%5$s">', esc_attr($option_key), esc_attr($section), esc_attr($name), esc_attr('connector'), esc_attr($connector)); $context_input = sprintf('<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" data-values=\'%5$s\' value="%6$s" class="select2-select with-source %4$s" data-placeholder="%7$s" data-group="%8$s" />', esc_attr($option_key), esc_attr($section), esc_attr($name), 'context', esc_attr(wp_stream_json_encode($context_values)), esc_attr($context), esc_html__('Any Context', 'stream'), 'connector'); // Action dropdown menu $action_values = array(); foreach ($this->get_terms_labels('action') as $action_id => $action_data) { $action_values[] = array('id' => $action_id, 'text' => $action_data); } $action_input = sprintf('<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" data-values=\'%5$s\' value="%6$s" class="select2-select with-source %4$s" data-placeholder="%7$s" />', esc_attr($option_key), esc_attr($section), esc_attr($name), 'action', esc_attr(wp_stream_json_encode($action_values)), esc_attr($action), esc_html__('Any Action', 'stream')); // IP Address input $ip_address_input = sprintf('<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" value="%5$s" class="select2-select %4$s" data-placeholder="%6$s" data-nonce="%7$s" />', esc_attr($option_key), esc_attr($section), esc_attr($name), 'ip_address', esc_attr($ip_address), esc_html__('Any IP Address', 'stream'), esc_attr(wp_create_nonce('stream_get_ips'))); // Hidden helper input $helper_input = sprintf('<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" value="" />', esc_attr($option_key), esc_attr($section), esc_attr($name), 'exclude_row'); $exclude_rows[] = sprintf('<tr class="%1$s %2$s"> <th scope="row" class="check-column">%3$s %4$s</th> <td>%5$s</td> <td>%6$s %7$s</td> <td>%8$s</td> <td>%9$s</td> <th scope="row" class="actions-column">%10$s</th> </tr>', 0 !== $key % 2 ? 'alternate' : '', 'helper' === $key ? 'hidden helper' : '', '<input class="cb-select" type="checkbox" />', $helper_input, $author_or_role_input, $connector_input, $context_input, $action_input, $ip_address_input, '<a href="#" class="exclude_rules_remove_rule_row">Delete</a>'); } $no_rules_found_row = sprintf('<tr class="no-items hidden"><td class="colspanchange" colspan="5">%1$s</td></tr>', esc_html__('No rules found.', 'stream')); $output .= '<thead>' . $heading_row . '</thead>'; $output .= '<tfoot>' . $heading_row . '</tfoot>'; $output .= '<tbody>' . $no_rules_found_row . implode('', $exclude_rows) . '</tbody>'; $output .= '</table>'; $output .= sprintf('<div class="tablenav bottom">%1$s</div>', $actions_bottom); break; } $output .= !empty($description) ? wp_kses_post(sprintf('<p class="description">%s</p>', $description)) : null; return $output; }
/** * @action wp_ajax_wp_stream_get_filter_value_by_id */ public function get_filter_value_by_id() { $filter = wp_stream_filter_input(INPUT_POST, 'filter'); switch ($filter) { case 'user_id': $id = wp_stream_filter_input(INPUT_POST, 'id'); if ('0' === $id) { $value = 'WP-CLI'; break; } $user = get_userdata($id); if (!$user || is_wp_error($user)) { $value = ''; } else { $value = $user->display_name; } break; default: $value = ''; } echo wp_stream_json_encode($value); // xss ok if (defined('WP_STREAM_TESTS') && WP_STREAM_TESTS) { return; } die; }
/** * Add class to highlight field by URL param * * @action admin_head */ public function highlight_field() { ?> <script> (function ($) { $(function () { var hashPrefix = <?php echo wp_stream_json_encode(self::HIGHLIGHT_FIELD_URL_HASH_PREFIX); ?> , hashFieldName = "", fieldNames = [], $select2Choices = {}, $field = {}; if (location.hash.substr(1, hashPrefix.length) === hashPrefix) { hashFieldName = location.hash.substr(hashPrefix.length + 1); fieldNames = [hashFieldName]; $field = $("input, textarea, select").filter(function () { return fieldNames.indexOf( $(this).attr("name") ) > -1; }); // try to find wp_stream field if ( $field.length === 0 ) { fieldNames = [ "wp_stream_" + hashFieldName, "wp_stream[" + hashFieldName + "]" ]; $field = $("input, textarea, select, div").filter(function () { return fieldNames.indexOf( $(this).attr("id") ) > -1; }); // if the field has been selectified, the list is the one to be colorized $select2Choices = $field.find(".select2-choices"); if ( $select2Choices.length === 1 ) { $field = $select2Choices; } } $("html, body") .animate({ scrollTop: ($field.closest("tr").length === 1 ? $field.closest("tr") : $field).offset().top - $("#wpadminbar").height() }, 1000, function () { $field .css("background", $(this).css("background-color")) .animate({ backgroundColor: "#fffedf", }, 250); $("label") .filter(function () { return fieldNames.indexOf( $(this).attr("for") ) > -1; }) .animate({ color: "#d54e21" }, 250); } ); } }); }(jQuery)); </script> <?php }
/** * Search for records * * @param array $query * * @return mixed Response body on success, or FALSE on failure */ private function search($query = array()) { if (!$this->is_connected()) { return false; } $defaults = array('sort' => array(array('created' => array('order' => 'asc')))); $last = get_option('wp_stream_last_migrated'); if ($last) { $defaults['filter'] = array('and' => array(array('range' => array('created' => array('gt' => $last))))); } $body['sites'] = array($this->site_uuid); $body['query'] = array_merge($defaults, (array) $query); $args = array('headers' => array('Stream-Site-API-Key' => $this->api_key, 'Content-Type' => 'application/json'), 'method' => 'POST', 'body' => wp_stream_json_encode($body), 'sslverify' => true); $response = wp_safe_remote_request('https://api.wp-stream.com/search', $args); if (is_wp_error($response)) { return false; } return json_decode(wp_remote_retrieve_body($response)); }
<?php header('Content-type: application/json; charset=' . get_option('blog_charset'), true); if (version_compare(PHP_VERSION, '5.4', '<')) { echo wp_stream_json_encode($records); // xss ok } else { echo wp_stream_json_encode($records, JSON_PRETTY_PRINT); // xss ok }