Version Description
March 15, 2017 =
New: Stream now support alternate Database Drivers. (#889)
Fix: Exclude dropdown menus (e5c8677, 3626ba8, e923a92)
Fix: Prevent loading of connectors on frontend (ed3a635)
Fix: Customizer performance issue (#898)
Fix: Various Network Admin bugs (#899)
Tweak: Codeclimate & Editorconfig support (#896)
Tweak: Better DB migration support (#905)
Download this release
Release Info
Developer | lukecarbis |
Plugin | Stream |
Version | 3.2.0 |
Comparing to | |
See all releases |
Code changes from version 3.1.1 to 3.2.0
- .codeclimate.yml +64 -0
- .editorconfig +21 -0
- .mailmap +0 -4
- alerts/class-alert-trigger-author.php +3 -2
- alerts/class-alert-trigger-context.php +3 -3
- classes/class-admin.php +4 -5
- classes/class-alerts-list.php +4 -0
- classes/class-alerts.php +3 -4
- classes/class-connector.php +14 -0
- classes/class-connectors.php +14 -1
- classes/class-db-driver-wpdb.php +168 -0
- classes/class-db-driver.php +53 -0
- classes/class-db.php +130 -112
- classes/class-form-generator.php +8 -8
- classes/class-list-table.php +2 -3
- classes/class-network.php +7 -1
- classes/class-plugin.php +33 -7
- classes/class-query.php +5 -84
- classes/class-settings.php +7 -1
- connectors/class-connector-blogs.php +7 -0
- connectors/class-connector-editor.php +7 -0
- connectors/class-connector-installer.php +7 -0
- connectors/class-connector-jetpack.php +7 -0
- connectors/class-connector-menus.php +7 -0
- connectors/class-connector-posts.php +7 -0
- connectors/class-connector-settings.php +7 -0
- connectors/class-connector-taxonomies.php +7 -0
- includes/db-updates.php +31 -22
- includes/functions.php +5 -3
- readme.txt +12 -2
- stream.php +1 -1
- ui/css/admin.css +17 -7
- ui/js/alerts.js +7 -8
- ui/js/exclude.js +58 -35
.codeclimate.yml
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
engines:
|
3 |
+
csslint:
|
4 |
+
enabled: true
|
5 |
+
duplication:
|
6 |
+
enabled: true
|
7 |
+
config:
|
8 |
+
languages:
|
9 |
+
- javascript
|
10 |
+
- php
|
11 |
+
fixme:
|
12 |
+
enabled: true
|
13 |
+
phpcodesniffer:
|
14 |
+
enabled: true
|
15 |
+
config:
|
16 |
+
standard: "WordPress-Core,WordPress-Docs,WordPress-Extra"
|
17 |
+
phpmd:
|
18 |
+
enabled: true
|
19 |
+
checks:
|
20 |
+
Controversial/CamelCaseParameterName:
|
21 |
+
enabled: false
|
22 |
+
Controversial/CamelCaseMethodName:
|
23 |
+
enabled: false
|
24 |
+
Controversial/CamelCasePropertyName:
|
25 |
+
enabled: false
|
26 |
+
Controversial/CamelCaseVariableName:
|
27 |
+
enabled: false
|
28 |
+
CleanCode/ElseExpression:
|
29 |
+
enabled: false
|
30 |
+
eslint:
|
31 |
+
enabled: true
|
32 |
+
channel: "eslint-2"
|
33 |
+
scss-lint:
|
34 |
+
enabled: true
|
35 |
+
markdownlint:
|
36 |
+
enabled: true
|
37 |
+
ratings:
|
38 |
+
paths:
|
39 |
+
- "**.css"
|
40 |
+
- "**.scss"
|
41 |
+
- "**.inc"
|
42 |
+
- "**.js"
|
43 |
+
- "**.jsx"
|
44 |
+
- "**.module"
|
45 |
+
- "**.php"
|
46 |
+
- "**.md"
|
47 |
+
- "**.py"
|
48 |
+
- "**.rb"
|
49 |
+
exclude_paths:
|
50 |
+
- "**.png"
|
51 |
+
- "**.jpg"
|
52 |
+
- "**.gif"
|
53 |
+
- "gulpfile.js"
|
54 |
+
- "composer.lock"
|
55 |
+
- "phpcs.xml"
|
56 |
+
- "**.json"
|
57 |
+
- "**.pot"
|
58 |
+
- "**.txt"
|
59 |
+
- "**-min.js"
|
60 |
+
- "**-min.css"
|
61 |
+
- "**.min.js"
|
62 |
+
- "**.min.css"
|
63 |
+
- "**.dist"
|
64 |
+
- "**.sh"
|
.editorconfig
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This file is for unifying the coding style for different editors and IDEs
|
2 |
+
# editorconfig.org
|
3 |
+
|
4 |
+
# WordPress Coding Standards
|
5 |
+
# https://make.wordpress.org/core/handbook/coding-standards/
|
6 |
+
|
7 |
+
root = true
|
8 |
+
|
9 |
+
[*]
|
10 |
+
charset = utf-8
|
11 |
+
end_of_line = lf
|
12 |
+
insert_final_newline = true
|
13 |
+
trim_trailing_whitespace = true
|
14 |
+
indent_style = tab
|
15 |
+
|
16 |
+
[{.jshintrc,*.json,*.yml}]
|
17 |
+
indent_style = space
|
18 |
+
indent_size = 2
|
19 |
+
|
20 |
+
[{*.txt,wp-config-sample.php}]
|
21 |
+
end_of_line = crlf
|
.mailmap
DELETED
@@ -1,4 +0,0 @@
|
|
1 |
-
Luke Carbis <luke@xwp.co> <Luke.Carbis@news.com.au>
|
2 |
-
Luke Carbis <luke@xwp.co> <luke.carbis@x-team.com.au>
|
3 |
-
Luke Carbis <luke@xwp.co> <luke.carbis@x-team.com>
|
4 |
-
Luke Carbis <luke@xwp.co> <luke@carbis.com.au>
|
|
|
|
|
|
|
|
alerts/class-alert-trigger-author.php
CHANGED
@@ -107,8 +107,9 @@ class Alert_Trigger_Author extends Alert_Trigger {
|
|
107 |
|
108 |
foreach ( $users as $user ) {
|
109 |
$all_records[] = array(
|
110 |
-
'id'
|
111 |
-
'
|
|
|
112 |
);
|
113 |
}
|
114 |
return $all_records;
|
107 |
|
108 |
foreach ( $users as $user ) {
|
109 |
$all_records[] = array(
|
110 |
+
'id' => $user->id,
|
111 |
+
'value' => $user->id,
|
112 |
+
'text' => $user->get_display_name(),
|
113 |
);
|
114 |
}
|
115 |
return $all_records;
|
alerts/class-alert-trigger-context.php
CHANGED
@@ -115,14 +115,14 @@ class Alert_Trigger_Context extends Alert_Trigger {
|
|
115 |
if ( isset( $context_data['children'] ) ) {
|
116 |
$child_values = array();
|
117 |
foreach ( $context_data['children'] as $child_id => $child_value ) {
|
118 |
-
$child_values[] = array( 'id' => $context_id . '-' . $child_id, 'text' => $child_value, 'parent' => $context_id );
|
119 |
}
|
120 |
}
|
121 |
if ( isset( $context_data['label'] ) ) {
|
122 |
-
$context_values[] = array( 'id' => $context_id, 'text' => $context_data['label'], 'children' => $child_values );
|
123 |
}
|
124 |
} else {
|
125 |
-
$context_values[] = array( 'id' => $context_id, 'text' => $context_data );
|
126 |
}
|
127 |
}
|
128 |
return $context_values;
|
115 |
if ( isset( $context_data['children'] ) ) {
|
116 |
$child_values = array();
|
117 |
foreach ( $context_data['children'] as $child_id => $child_value ) {
|
118 |
+
$child_values[] = array( 'value' => $context_id . '-' . $child_id, 'id' => $context_id . '-' . $child_id, 'text' => $child_value, 'parent' => $context_id );
|
119 |
}
|
120 |
}
|
121 |
if ( isset( $context_data['label'] ) ) {
|
122 |
+
$context_values[] = array( 'value' => $context_id, 'id' => $context_id, 'text' => $context_data['label'], 'children' => $child_values );
|
123 |
}
|
124 |
} else {
|
125 |
+
$context_values[] = array( 'value' => $context_id, 'id' => $context_id, 'text' => $context_data );
|
126 |
}
|
127 |
}
|
128 |
return $context_values;
|
classes/class-admin.php
CHANGED
@@ -162,8 +162,7 @@ class Admin {
|
|
162 |
add_action( 'wp_ajax_wp_stream_reset', array( $this, 'wp_ajax_reset' ) );
|
163 |
|
164 |
// Uninstall Streams and Deactivate plugin.
|
165 |
-
$uninstall =
|
166 |
-
add_action( 'wp_ajax_wp_stream_uninstall', array( $uninstall, 'uninstall' ) );
|
167 |
|
168 |
// Auto purge setup.
|
169 |
add_action( 'wp_loaded', array( $this, 'purge_schedule_setup' ) );
|
@@ -346,8 +345,8 @@ class Admin {
|
|
346 |
* @return void
|
347 |
*/
|
348 |
public function admin_enqueue_scripts( $hook ) {
|
349 |
-
wp_register_script( 'wp-stream-select2', $this->plugin->locations['url'] . 'ui/lib/select2/js/select2.js', array( 'jquery' ), '3.5.2', true );
|
350 |
-
wp_register_style( 'wp-stream-select2', $this->plugin->locations['url'] . 'ui/lib/select2/css/select2.css', array(), '3.5.2' );
|
351 |
wp_register_script( 'wp-stream-timeago', $this->plugin->locations['url'] . 'ui/lib/timeago/jquery.timeago.js', array(), '1.4.1', true );
|
352 |
|
353 |
$locale = strtolower( substr( get_locale(), 0, 2 ) );
|
@@ -442,7 +441,7 @@ class Admin {
|
|
442 |
}
|
443 |
|
444 |
$screen = get_current_screen();
|
445 |
-
if ( is_admin() &&
|
446 |
return true;
|
447 |
}
|
448 |
|
162 |
add_action( 'wp_ajax_wp_stream_reset', array( $this, 'wp_ajax_reset' ) );
|
163 |
|
164 |
// Uninstall Streams and Deactivate plugin.
|
165 |
+
$uninstall = $this->plugin->db->driver->purge_storage( $this->plugin );
|
|
|
166 |
|
167 |
// Auto purge setup.
|
168 |
add_action( 'wp_loaded', array( $this, 'purge_schedule_setup' ) );
|
345 |
* @return void
|
346 |
*/
|
347 |
public function admin_enqueue_scripts( $hook ) {
|
348 |
+
wp_register_script( 'wp-stream-select2', $this->plugin->locations['url'] . 'ui/lib/select2/js/select2.full.min.js', array( 'jquery' ), '3.5.2', true );
|
349 |
+
wp_register_style( 'wp-stream-select2', $this->plugin->locations['url'] . 'ui/lib/select2/css/select2.min.css', array(), '3.5.2' );
|
350 |
wp_register_script( 'wp-stream-timeago', $this->plugin->locations['url'] . 'ui/lib/timeago/jquery.timeago.js', array(), '1.4.1', true );
|
351 |
|
352 |
$locale = strtolower( substr( get_locale(), 0, 2 ) );
|
441 |
}
|
442 |
|
443 |
$screen = get_current_screen();
|
444 |
+
if ( is_admin() && Alerts::POST_TYPE === $screen->post_type ) {
|
445 |
return true;
|
446 |
}
|
447 |
|
classes/class-alerts-list.php
CHANGED
@@ -334,6 +334,10 @@ class Alerts_List {
|
|
334 |
* @return array
|
335 |
*/
|
336 |
function save_alert_inline_edit( $data, $postarr ) {
|
|
|
|
|
|
|
|
|
337 |
$post_id = $postarr['ID'];
|
338 |
$post_type = wp_stream_filter_input( INPUT_POST, 'post_type' );
|
339 |
if ( Alerts::POST_TYPE !== $post_type ) {
|
334 |
* @return array
|
335 |
*/
|
336 |
function save_alert_inline_edit( $data, $postarr ) {
|
337 |
+
if ( did_action( 'customize_preview_init' ) ) {
|
338 |
+
return $data;
|
339 |
+
}
|
340 |
+
|
341 |
$post_id = $postarr['ID'];
|
342 |
$post_type = wp_stream_filter_input( INPUT_POST, 'post_type' );
|
343 |
if ( Alerts::POST_TYPE !== $post_type ) {
|
classes/class-alerts.php
CHANGED
@@ -426,8 +426,7 @@ class Alerts {
|
|
426 |
}
|
427 |
|
428 |
// Get the first existing Site in the Network.
|
429 |
-
|
430 |
-
$sites = wp_get_sites(
|
431 |
array(
|
432 |
'limit' => 5, // Limit the size of the query.
|
433 |
)
|
@@ -436,8 +435,8 @@ class Alerts {
|
|
436 |
$site_id = '1';
|
437 |
|
438 |
// Function wp_get_sites() can return an empty array if the network is too large.
|
439 |
-
if ( ! empty( $sites ) && ! empty( $sites[0]
|
440 |
-
$site_id = $sites[0]
|
441 |
}
|
442 |
|
443 |
$new_url = get_admin_url( $site_id, $page );
|
426 |
}
|
427 |
|
428 |
// Get the first existing Site in the Network.
|
429 |
+
$sites = wp_stream_get_sites(
|
|
|
430 |
array(
|
431 |
'limit' => 5, // Limit the size of the query.
|
432 |
)
|
435 |
$site_id = '1';
|
436 |
|
437 |
// Function wp_get_sites() can return an empty array if the network is too large.
|
438 |
+
if ( ! empty( $sites ) && ! empty( $sites[0]->blog_id ) ) {
|
439 |
+
$site_id = $sites[0]->blog_id;
|
440 |
}
|
441 |
|
442 |
$new_url = get_admin_url( $site_id, $page );
|
classes/class-connector.php
CHANGED
@@ -30,6 +30,20 @@ abstract class Connector {
|
|
30 |
*/
|
31 |
public $prev_stream = null;
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
/**
|
34 |
* Register all context hooks
|
35 |
*/
|
30 |
*/
|
31 |
public $prev_stream = null;
|
32 |
|
33 |
+
/**
|
34 |
+
* Register connector in the WP Admin
|
35 |
+
*
|
36 |
+
* @var bool
|
37 |
+
*/
|
38 |
+
public $register_admin = true;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Register connector in the WP Frontend
|
42 |
+
*
|
43 |
+
* @var bool
|
44 |
+
*/
|
45 |
+
public $register_frontend = true;
|
46 |
+
|
47 |
/**
|
48 |
* Register all context hooks
|
49 |
*/
|
classes/class-connectors.php
CHANGED
@@ -89,9 +89,22 @@ class Connectors {
|
|
89 |
continue;
|
90 |
}
|
91 |
$class = new $class_name( $this->plugin->log );
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
continue;
|
94 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
if ( $class->is_dependency_satisfied() ) {
|
96 |
$classes[ $class->name ] = $class;
|
97 |
}
|
89 |
continue;
|
90 |
}
|
91 |
$class = new $class_name( $this->plugin->log );
|
92 |
+
|
93 |
+
// Check if the Connector extends WP_Stream\Connector
|
94 |
+
if ( ! is_subclass_of( $class, 'WP_Stream\Connector' ) ) {
|
95 |
+
continue;
|
96 |
+
}
|
97 |
+
|
98 |
+
// Check if the Connector is allowed to be registered in the WP Admin
|
99 |
+
if ( is_admin() && ! $class->register_admin ) {
|
100 |
continue;
|
101 |
}
|
102 |
+
|
103 |
+
// Check if the Connector is allowed to be registered in the WP Frontend
|
104 |
+
if ( ! is_admin() && ! $class->register_frontend ) {
|
105 |
+
continue;
|
106 |
+
}
|
107 |
+
|
108 |
if ( $class->is_dependency_satisfied() ) {
|
109 |
$classes[ $class->name ] = $class;
|
110 |
}
|
classes/class-db-driver-wpdb.php
ADDED
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace WP_Stream;
|
3 |
+
|
4 |
+
class DB_Driver_WPDB implements DB_Driver {
|
5 |
+
/**
|
6 |
+
* Holds Query class
|
7 |
+
*
|
8 |
+
* @var Query
|
9 |
+
*/
|
10 |
+
protected $query;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Hold records table name
|
14 |
+
*
|
15 |
+
* @var string
|
16 |
+
*/
|
17 |
+
public $table;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Hold meta table name
|
21 |
+
*
|
22 |
+
* @var string
|
23 |
+
*/
|
24 |
+
public $table_meta;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Class constructor.
|
28 |
+
*/
|
29 |
+
public function __construct() {
|
30 |
+
$this->query = new Query( $this );
|
31 |
+
|
32 |
+
global $wpdb;
|
33 |
+
$prefix = apply_filters( 'wp_stream_db_tables_prefix', $wpdb->base_prefix );
|
34 |
+
|
35 |
+
$this->table = $prefix . 'stream';
|
36 |
+
$this->table_meta = $prefix . 'stream_meta';
|
37 |
+
|
38 |
+
$wpdb->stream = $this->table;
|
39 |
+
$wpdb->streammeta = $this->table_meta;
|
40 |
+
|
41 |
+
// Hack for get_metadata
|
42 |
+
$wpdb->recordmeta = $this->table_meta;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Insert a record.
|
47 |
+
*
|
48 |
+
* @param array $data Data to insert.
|
49 |
+
*
|
50 |
+
* @return int
|
51 |
+
*/
|
52 |
+
public function insert_record( $data ) {
|
53 |
+
global $wpdb;
|
54 |
+
|
55 |
+
if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
|
56 |
+
return false;
|
57 |
+
}
|
58 |
+
|
59 |
+
$meta = $data['meta'];
|
60 |
+
unset( $data['meta'] );
|
61 |
+
|
62 |
+
$result = $wpdb->insert( $this->table, $data );
|
63 |
+
if ( ! $result ) {
|
64 |
+
return false;
|
65 |
+
}
|
66 |
+
|
67 |
+
$record_id = $wpdb->insert_id;
|
68 |
+
|
69 |
+
// Insert record meta
|
70 |
+
foreach ( (array) $meta as $key => $vals ) {
|
71 |
+
foreach ( (array) $vals as $val ) {
|
72 |
+
$this->insert_meta( $record_id, $key, $val );
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
return $record_id;
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Insert record meta
|
81 |
+
*
|
82 |
+
* @param int $record_id
|
83 |
+
* @param string $key
|
84 |
+
* @param string $val
|
85 |
+
*
|
86 |
+
* @return array
|
87 |
+
*/
|
88 |
+
public function insert_meta( $record_id, $key, $val ) {
|
89 |
+
global $wpdb;
|
90 |
+
|
91 |
+
$result = $wpdb->insert(
|
92 |
+
$this->table_meta,
|
93 |
+
array(
|
94 |
+
'record_id' => $record_id,
|
95 |
+
'meta_key' => $key,
|
96 |
+
'meta_value' => $val,
|
97 |
+
)
|
98 |
+
);
|
99 |
+
|
100 |
+
return $result;
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Retrieve records
|
105 |
+
*
|
106 |
+
* @param array $args
|
107 |
+
*
|
108 |
+
* @return array
|
109 |
+
*/
|
110 |
+
public function get_records( $args ) {
|
111 |
+
return $this->query->query( $args );
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Returns array of existing values for requested column.
|
116 |
+
* Used to fill search filters with only used items, instead of all items.
|
117 |
+
*
|
118 |
+
* GROUP BY allows query to find just the first occurrence of each value in the column,
|
119 |
+
* increasing the efficiency of the query.
|
120 |
+
*
|
121 |
+
* @param string $column
|
122 |
+
*
|
123 |
+
* @return array
|
124 |
+
*/
|
125 |
+
public function get_column_values( $column ) {
|
126 |
+
global $wpdb;
|
127 |
+
return (array) $wpdb->get_results(
|
128 |
+
"SELECT DISTINCT $column FROM $wpdb->stream", // @codingStandardsIgnoreLine can't prepare column name
|
129 |
+
'ARRAY_A'
|
130 |
+
);
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Public getter to return table names
|
135 |
+
*
|
136 |
+
* @return array
|
137 |
+
*/
|
138 |
+
public function get_table_names() {
|
139 |
+
return array(
|
140 |
+
$this->table,
|
141 |
+
$this->table_meta,
|
142 |
+
);
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Init storage.
|
147 |
+
*
|
148 |
+
* @param \WP_Stream\Plugin $plugin Instance of the plugin.
|
149 |
+
* @return \WP_Stream\Install
|
150 |
+
*/
|
151 |
+
public function setup_storage( $plugin ) {
|
152 |
+
return new Install( $plugin );
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Purge storage.
|
157 |
+
*
|
158 |
+
* @param \WP_Stream\Plugin $plugin Instance of the plugin.
|
159 |
+
* @return \WP_Stream\Uninstall
|
160 |
+
*/
|
161 |
+
public function purge_storage( $plugin ) {
|
162 |
+
$uninstall = new Uninstall( $plugin );
|
163 |
+
add_action( 'wp_ajax_wp_stream_uninstall', array( $uninstall, 'uninstall' ) );
|
164 |
+
|
165 |
+
return $uninstall;
|
166 |
+
}
|
167 |
+
|
168 |
+
}
|
classes/class-db-driver.php
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace WP_Stream;
|
3 |
+
|
4 |
+
interface DB_Driver {
|
5 |
+
/**
|
6 |
+
* Insert a record
|
7 |
+
*
|
8 |
+
* @param array $data
|
9 |
+
*
|
10 |
+
* @return int
|
11 |
+
*/
|
12 |
+
public function insert_record( $data );
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Retrieve records
|
16 |
+
*
|
17 |
+
* @param array $args
|
18 |
+
*
|
19 |
+
* @return array
|
20 |
+
*/
|
21 |
+
public function get_records( $args );
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Returns array of existing values for requested column.
|
25 |
+
* Used to fill search filters with only used items, instead of all items.
|
26 |
+
*
|
27 |
+
* @param string $column
|
28 |
+
*
|
29 |
+
* @return array
|
30 |
+
*/
|
31 |
+
public function get_column_values( $column );
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Public getter to return table names
|
35 |
+
*
|
36 |
+
* @return array
|
37 |
+
*/
|
38 |
+
public function get_table_names();
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Init storage.
|
42 |
+
*
|
43 |
+
* @param \WP_Stream\Plugin $plugin Instance of the plugin.
|
44 |
+
*/
|
45 |
+
public function setup_storage( $plugin );
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Purge storage.
|
49 |
+
*
|
50 |
+
* @param \WP_Stream\Plugin $plugin Instance of the plugin.
|
51 |
+
*/
|
52 |
+
public function purge_storage( $plugin );
|
53 |
+
}
|
classes/class-db.php
CHANGED
@@ -3,71 +3,26 @@ namespace WP_Stream;
|
|
3 |
|
4 |
class DB {
|
5 |
/**
|
6 |
-
* Hold
|
7 |
-
* @var Plugin
|
8 |
-
*/
|
9 |
-
public $plugin;
|
10 |
-
|
11 |
-
/**
|
12 |
-
* Hold Query class
|
13 |
-
* @var Query
|
14 |
-
*/
|
15 |
-
public $query;
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Hold records table name
|
19 |
*
|
20 |
-
* @var
|
21 |
*/
|
22 |
-
public $
|
23 |
|
24 |
/**
|
25 |
-
*
|
26 |
*
|
27 |
-
* @var
|
28 |
*/
|
29 |
-
|
30 |
|
31 |
/**
|
32 |
* Class constructor.
|
33 |
*
|
34 |
-
* @param
|
35 |
-
*/
|
36 |
-
public function __construct( $plugin ) {
|
37 |
-
$this->plugin = $plugin;
|
38 |
-
$this->query = new Query( $this );
|
39 |
-
|
40 |
-
global $wpdb;
|
41 |
-
|
42 |
-
/**
|
43 |
-
* Allows devs to alter the tables prefix, default to base_prefix
|
44 |
-
*
|
45 |
-
* @param string $prefix
|
46 |
-
*
|
47 |
-
* @return string
|
48 |
-
*/
|
49 |
-
$prefix = apply_filters( 'wp_stream_db_tables_prefix', $wpdb->base_prefix );
|
50 |
-
|
51 |
-
$this->table = $prefix . 'stream';
|
52 |
-
$this->table_meta = $prefix . 'stream_meta';
|
53 |
-
|
54 |
-
$wpdb->stream = $this->table;
|
55 |
-
$wpdb->streammeta = $this->table_meta;
|
56 |
-
|
57 |
-
// Hack for get_metadata
|
58 |
-
$wpdb->recordmeta = $this->table_meta;
|
59 |
-
}
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Public getter to return table names
|
63 |
-
*
|
64 |
-
* @return array
|
65 |
*/
|
66 |
-
public function
|
67 |
-
|
68 |
-
$this->table,
|
69 |
-
$this->table_meta,
|
70 |
-
);
|
71 |
}
|
72 |
|
73 |
/**
|
@@ -101,37 +56,34 @@ class DB {
|
|
101 |
return false;
|
102 |
}
|
103 |
|
104 |
-
global $wpdb;
|
105 |
-
|
106 |
$fields = array( 'object_id', 'site_id', 'blog_id', 'user_id', 'user_role', 'created', 'summary', 'ip', 'connector', 'context', 'action' );
|
107 |
$data = array_intersect_key( $record, array_flip( $fields ) );
|
108 |
|
109 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
|
111 |
-
if (
|
112 |
/**
|
113 |
* Fires on a record insertion error
|
114 |
*
|
115 |
* @param array $record
|
116 |
* @param mixed $result
|
117 |
*/
|
118 |
-
do_action( 'wp_stream_record_insert_error', $record,
|
119 |
-
|
120 |
-
return $result;
|
121 |
-
}
|
122 |
-
|
123 |
-
$record_id = $wpdb->insert_id;
|
124 |
|
125 |
-
|
126 |
-
foreach ( (array) $record['meta'] as $key => $vals ) {
|
127 |
-
// If associative array, serialize it, otherwise loop on its members
|
128 |
-
$vals = ( is_array( $vals ) && 0 !== key( $vals ) ) ? array( $vals ) : $vals;
|
129 |
-
|
130 |
-
foreach ( (array) $vals as $val ) {
|
131 |
-
$val = maybe_serialize( $val );
|
132 |
-
|
133 |
-
$this->insert_meta( $record_id, $key, $val );
|
134 |
-
}
|
135 |
}
|
136 |
|
137 |
/**
|
@@ -145,35 +97,11 @@ class DB {
|
|
145 |
return absint( $record_id );
|
146 |
}
|
147 |
|
148 |
-
/**
|
149 |
-
* Insert record meta
|
150 |
-
*
|
151 |
-
* @param int $record_id
|
152 |
-
* @param string $key
|
153 |
-
* @param string $val
|
154 |
-
*
|
155 |
-
* @return array
|
156 |
-
*/
|
157 |
-
public function insert_meta( $record_id, $key, $val ) {
|
158 |
-
global $wpdb;
|
159 |
-
|
160 |
-
$result = $wpdb->insert(
|
161 |
-
$this->table_meta,
|
162 |
-
array(
|
163 |
-
'record_id' => $record_id,
|
164 |
-
'meta_key' => $key,
|
165 |
-
'meta_value' => $val,
|
166 |
-
)
|
167 |
-
);
|
168 |
-
|
169 |
-
return $result;
|
170 |
-
}
|
171 |
-
|
172 |
/**
|
173 |
* Returns array of existing values for requested column.
|
174 |
* Used to fill search filters with only used items, instead of all items.
|
175 |
*
|
176 |
-
* GROUP BY allows query to find just the first
|
177 |
* increasing the efficiency of the query.
|
178 |
*
|
179 |
* @see assemble_records
|
@@ -183,19 +111,14 @@ class DB {
|
|
183 |
*
|
184 |
* @return array
|
185 |
*/
|
186 |
-
function existing_records( $column ) {
|
187 |
-
global $wpdb;
|
188 |
-
|
189 |
// Sanitize column
|
190 |
$allowed_columns = array( 'ID', 'site_id', 'blog_id', 'object_id', 'user_id', 'user_role', 'created', 'summary', 'connector', 'context', 'action', 'ip' );
|
191 |
if ( ! in_array( $column, $allowed_columns, true ) ) {
|
192 |
return array();
|
193 |
}
|
194 |
|
195 |
-
$rows = $
|
196 |
-
"SELECT DISTINCT $column FROM $wpdb->stream", // @codingStandardsIgnoreLine can't prepare column name
|
197 |
-
'ARRAY_A'
|
198 |
-
);
|
199 |
|
200 |
if ( is_array( $rows ) && ! empty( $rows ) ) {
|
201 |
$output_array = array();
|
@@ -211,19 +134,114 @@ class DB {
|
|
211 |
|
212 |
$column = sprintf( 'stream_%s', $column );
|
213 |
|
214 |
-
|
|
|
215 |
}
|
216 |
|
217 |
/**
|
218 |
-
*
|
219 |
-
*
|
220 |
-
* @see Query->query()
|
221 |
*
|
222 |
* @param array Query args
|
223 |
*
|
224 |
* @return array Stream Records
|
225 |
*/
|
226 |
-
function
|
227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
}
|
229 |
}
|
3 |
|
4 |
class DB {
|
5 |
/**
|
6 |
+
* Hold the Driver class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
*
|
8 |
+
* @var DB_Driver
|
9 |
*/
|
10 |
+
public $driver;
|
11 |
|
12 |
/**
|
13 |
+
* Number of records in last request
|
14 |
*
|
15 |
+
* @var int
|
16 |
*/
|
17 |
+
protected $found_records_count = 0;
|
18 |
|
19 |
/**
|
20 |
* Class constructor.
|
21 |
*
|
22 |
+
* @param DB_Driver $driver Driver we want to use.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
*/
|
24 |
+
public function __construct( $driver ) {
|
25 |
+
$this->driver = $driver;
|
|
|
|
|
|
|
26 |
}
|
27 |
|
28 |
/**
|
56 |
return false;
|
57 |
}
|
58 |
|
|
|
|
|
59 |
$fields = array( 'object_id', 'site_id', 'blog_id', 'user_id', 'user_role', 'created', 'summary', 'ip', 'connector', 'context', 'action' );
|
60 |
$data = array_intersect_key( $record, array_flip( $fields ) );
|
61 |
|
62 |
+
$meta = array();
|
63 |
+
foreach ( (array) $record['meta'] as $key => $vals ) {
|
64 |
+
// If associative array, serialize it, otherwise loop on its members
|
65 |
+
$vals = ( is_array( $vals ) && 0 !== key( $vals ) ) ? array( $vals ) : $vals;
|
66 |
+
|
67 |
+
foreach ( (array) $vals as $num => $val ) {
|
68 |
+
$vals[ $num ] = maybe_serialize( $val );
|
69 |
+
}
|
70 |
+
$meta[ $key ] = $vals;
|
71 |
+
}
|
72 |
+
|
73 |
+
$data['meta'] = $meta;
|
74 |
+
|
75 |
+
$record_id = $this->driver->insert_record( $data );
|
76 |
|
77 |
+
if ( ! $record_id ) {
|
78 |
/**
|
79 |
* Fires on a record insertion error
|
80 |
*
|
81 |
* @param array $record
|
82 |
* @param mixed $result
|
83 |
*/
|
84 |
+
do_action( 'wp_stream_record_insert_error', $record, false );
|
|
|
|
|
|
|
|
|
|
|
85 |
|
86 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
|
89 |
/**
|
97 |
return absint( $record_id );
|
98 |
}
|
99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
/**
|
101 |
* Returns array of existing values for requested column.
|
102 |
* Used to fill search filters with only used items, instead of all items.
|
103 |
*
|
104 |
+
* GROUP BY allows query to find just the first occurrence of each value in the column,
|
105 |
* increasing the efficiency of the query.
|
106 |
*
|
107 |
* @see assemble_records
|
111 |
*
|
112 |
* @return array
|
113 |
*/
|
114 |
+
public function existing_records( $column ) {
|
|
|
|
|
115 |
// Sanitize column
|
116 |
$allowed_columns = array( 'ID', 'site_id', 'blog_id', 'object_id', 'user_id', 'user_role', 'created', 'summary', 'connector', 'context', 'action', 'ip' );
|
117 |
if ( ! in_array( $column, $allowed_columns, true ) ) {
|
118 |
return array();
|
119 |
}
|
120 |
|
121 |
+
$rows = $this->driver->get_column_values( $column );
|
|
|
|
|
|
|
122 |
|
123 |
if ( is_array( $rows ) && ! empty( $rows ) ) {
|
124 |
$output_array = array();
|
134 |
|
135 |
$column = sprintf( 'stream_%s', $column );
|
136 |
|
137 |
+
$term_labels = wp_stream_get_instance()->connectors->term_labels;
|
138 |
+
return isset( $term_labels[ $column ] ) ? $term_labels[ $column ] : array();
|
139 |
}
|
140 |
|
141 |
/**
|
142 |
+
* Get stream records
|
|
|
|
|
143 |
*
|
144 |
* @param array Query args
|
145 |
*
|
146 |
* @return array Stream Records
|
147 |
*/
|
148 |
+
public function get_records( $args ) {
|
149 |
+
$defaults = array(
|
150 |
+
// Search param
|
151 |
+
'search' => null,
|
152 |
+
'search_field' => 'summary',
|
153 |
+
'record_after' => null, // Deprecated, use date_after instead
|
154 |
+
// Date-based filters
|
155 |
+
'date' => null, // Ex: 2015-07-01
|
156 |
+
'date_from' => null, // Ex: 2015-07-01
|
157 |
+
'date_to' => null, // Ex: 2015-07-01
|
158 |
+
'date_after' => null, // Ex: 2015-07-01T15:19:21+00:00
|
159 |
+
'date_before' => null, // Ex: 2015-07-01T15:19:21+00:00
|
160 |
+
// Record ID filters
|
161 |
+
'record' => null,
|
162 |
+
'record__in' => array(),
|
163 |
+
'record__not_in' => array(),
|
164 |
+
// Pagination params
|
165 |
+
'records_per_page' => get_option( 'posts_per_page', 20 ),
|
166 |
+
'paged' => 1,
|
167 |
+
// Order
|
168 |
+
'order' => 'desc',
|
169 |
+
'orderby' => 'date',
|
170 |
+
// Fields selection
|
171 |
+
'fields' => array(),
|
172 |
+
);
|
173 |
+
|
174 |
+
// Additional property fields
|
175 |
+
$properties = array(
|
176 |
+
'user_id' => null,
|
177 |
+
'user_role' => null,
|
178 |
+
'ip' => null,
|
179 |
+
'object_id' => null,
|
180 |
+
'site_id' => null,
|
181 |
+
'blog_id' => null,
|
182 |
+
'connector' => null,
|
183 |
+
'context' => null,
|
184 |
+
'action' => null,
|
185 |
+
);
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Filter allows additional query properties to be added
|
189 |
+
*
|
190 |
+
* @return array Array of query properties
|
191 |
+
*/
|
192 |
+
$properties = apply_filters( 'wp_stream_query_properties', $properties );
|
193 |
+
|
194 |
+
// Add property fields to defaults, including their __in/__not_in variations
|
195 |
+
foreach ( $properties as $property => $default ) {
|
196 |
+
if ( ! isset( $defaults[ $property ] ) ) {
|
197 |
+
$defaults[ $property ] = $default;
|
198 |
+
}
|
199 |
+
|
200 |
+
$defaults[ "{$property}__in" ] = array();
|
201 |
+
$defaults[ "{$property}__not_in" ] = array();
|
202 |
+
}
|
203 |
+
|
204 |
+
$args = wp_parse_args( $args, $defaults );
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Filter allows additional arguments to query $args
|
208 |
+
*
|
209 |
+
* @return array Array of query arguments
|
210 |
+
*/
|
211 |
+
$args = apply_filters( 'wp_stream_query_args', $args );
|
212 |
+
|
213 |
+
$result = (array) $this->driver->get_records( $args );
|
214 |
+
$this->found_records_count = isset( $result['count'] ) ? $result['count'] : 0;
|
215 |
+
|
216 |
+
return empty( $result['items'] ) ? array() : $result['items'];
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Helper function, backwards compatibility
|
221 |
+
*
|
222 |
+
* @param array $args Query args
|
223 |
+
*
|
224 |
+
* @return array Stream Records
|
225 |
+
*/
|
226 |
+
public function query( $args ) {
|
227 |
+
return $this->get_records( $args );
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Return the number of records found in last request
|
232 |
+
*
|
233 |
+
* return int
|
234 |
+
*/
|
235 |
+
public function get_found_records_count() {
|
236 |
+
return $this->found_records_count;
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Public getter to return table names
|
241 |
+
*
|
242 |
+
* @return array
|
243 |
+
*/
|
244 |
+
public function get_table_names() {
|
245 |
+
return $this->driver->get_table_names();
|
246 |
}
|
247 |
}
|
classes/class-form-generator.php
CHANGED
@@ -133,30 +133,30 @@ class Form_Generator {
|
|
133 |
'text' => '',
|
134 |
'children' => array(),
|
135 |
) );
|
136 |
-
if ( empty( $parent['
|
137 |
continue;
|
138 |
}
|
139 |
if ( is_array( $args['value'] ) ) {
|
140 |
-
$selected = selected( in_array( $parent['
|
141 |
} else {
|
142 |
-
$selected = selected( $args['value'], $parent['
|
143 |
}
|
144 |
$output .= sprintf(
|
145 |
'<option class="parent" value="%1$s" %3$s>%2$s</option>',
|
146 |
-
$parent['
|
147 |
$parent['text'],
|
148 |
$selected
|
149 |
);
|
150 |
-
$values[] = $parent['
|
151 |
if ( ! empty( $parent['children'] ) ) {
|
152 |
foreach ( $parent['children'] as $child ) {
|
153 |
$output .= sprintf(
|
154 |
'<option class="child" value="%1$s" %3$s>%2$s</option>',
|
155 |
-
$child['
|
156 |
$child['text'],
|
157 |
-
selected( $args['value'], $child['
|
158 |
);
|
159 |
-
$values[] = $child['
|
160 |
}
|
161 |
$output .= '</optgroup>';
|
162 |
}
|
133 |
'text' => '',
|
134 |
'children' => array(),
|
135 |
) );
|
136 |
+
if ( empty( $parent['value'] ) ) {
|
137 |
continue;
|
138 |
}
|
139 |
if ( is_array( $args['value'] ) ) {
|
140 |
+
$selected = selected( in_array( $parent['value'], $args['value'], true ), true, false );
|
141 |
} else {
|
142 |
+
$selected = selected( $args['value'], $parent['value'], false );
|
143 |
}
|
144 |
$output .= sprintf(
|
145 |
'<option class="parent" value="%1$s" %3$s>%2$s</option>',
|
146 |
+
$parent['value'],
|
147 |
$parent['text'],
|
148 |
$selected
|
149 |
);
|
150 |
+
$values[] = $parent['value'];
|
151 |
if ( ! empty( $parent['children'] ) ) {
|
152 |
foreach ( $parent['children'] as $child ) {
|
153 |
$output .= sprintf(
|
154 |
'<option class="child" value="%1$s" %3$s>%2$s</option>',
|
155 |
+
$child['value'],
|
156 |
$child['text'],
|
157 |
+
selected( $args['value'], $child['value'], false )
|
158 |
);
|
159 |
+
$values[] = $child['value'];
|
160 |
}
|
161 |
$output .= '</optgroup>';
|
162 |
}
|
classes/class-list-table.php
CHANGED
@@ -206,8 +206,7 @@ class List_Table extends \WP_List_Table {
|
|
206 |
}
|
207 |
$args['records_per_page'] = apply_filters( 'stream_records_per_page', $args['records_per_page'] );
|
208 |
|
209 |
-
$items = $this->plugin->db->
|
210 |
-
|
211 |
return $items;
|
212 |
}
|
213 |
|
@@ -217,7 +216,7 @@ class List_Table extends \WP_List_Table {
|
|
217 |
* @return integer
|
218 |
*/
|
219 |
public function get_total_found_rows() {
|
220 |
-
return $this->plugin->db->
|
221 |
}
|
222 |
|
223 |
function column_default( $item, $column_name ) {
|
206 |
}
|
207 |
$args['records_per_page'] = apply_filters( 'stream_records_per_page', $args['records_per_page'] );
|
208 |
|
209 |
+
$items = $this->plugin->db->get_records( $args );
|
|
|
210 |
return $items;
|
211 |
}
|
212 |
|
216 |
* @return integer
|
217 |
*/
|
218 |
public function get_total_found_rows() {
|
219 |
+
return $this->plugin->db->get_found_records_count();
|
220 |
}
|
221 |
|
222 |
function column_default( $item, $column_name ) {
|
classes/class-network.php
CHANGED
@@ -51,6 +51,8 @@ class Network {
|
|
51 |
/**
|
52 |
* Workaround to get admin-ajax.php to know when the request is from the Network Admin
|
53 |
*
|
|
|
|
|
54 |
* @action init
|
55 |
*
|
56 |
* @see https://core.trac.wordpress.org/ticket/22589
|
@@ -64,7 +66,10 @@ class Network {
|
|
64 |
preg_match( '#^' . network_admin_url() . '#i', $_SERVER['HTTP_REFERER'] )
|
65 |
) {
|
66 |
define( 'WP_NETWORK_ADMIN', true );
|
|
|
67 |
}
|
|
|
|
|
68 |
}
|
69 |
|
70 |
/**
|
@@ -136,6 +141,7 @@ class Network {
|
|
136 |
}
|
137 |
|
138 |
remove_submenu_page( $this->plugin->admin->records_page_slug, 'wp_stream_settings' );
|
|
|
139 |
|
140 |
$this->plugin->admin->screen_id['network_settings'] = add_submenu_page(
|
141 |
$this->plugin->admin->records_page_slug,
|
@@ -496,7 +502,7 @@ class Network {
|
|
496 |
* @return mixed
|
497 |
*/
|
498 |
public function network_admin_columns( $columns ) {
|
499 |
-
if ( is_network_admin() ) {
|
500 |
$columns = array_merge(
|
501 |
array_slice( $columns, 0, -1 ),
|
502 |
array(
|
51 |
/**
|
52 |
* Workaround to get admin-ajax.php to know when the request is from the Network Admin
|
53 |
*
|
54 |
+
* @return bool
|
55 |
+
*
|
56 |
* @action init
|
57 |
*
|
58 |
* @see https://core.trac.wordpress.org/ticket/22589
|
66 |
preg_match( '#^' . network_admin_url() . '#i', $_SERVER['HTTP_REFERER'] )
|
67 |
) {
|
68 |
define( 'WP_NETWORK_ADMIN', true );
|
69 |
+
return WP_NETWORK_ADMIN;
|
70 |
}
|
71 |
+
|
72 |
+
return false;
|
73 |
}
|
74 |
|
75 |
/**
|
141 |
}
|
142 |
|
143 |
remove_submenu_page( $this->plugin->admin->records_page_slug, 'wp_stream_settings' );
|
144 |
+
remove_submenu_page( $this->plugin->admin->records_page_slug, 'edit.php?post_type=wp_stream_alerts' );
|
145 |
|
146 |
$this->plugin->admin->screen_id['network_settings'] = add_submenu_page(
|
147 |
$this->plugin->admin->records_page_slug,
|
502 |
* @return mixed
|
503 |
*/
|
504 |
public function network_admin_columns( $columns ) {
|
505 |
+
if ( is_network_admin() || $this->ajax_network_admin() ) {
|
506 |
$columns = array_merge(
|
507 |
array_slice( $columns, 0, -1 ),
|
508 |
array(
|
classes/class-plugin.php
CHANGED
@@ -7,7 +7,7 @@ class Plugin {
|
|
7 |
*
|
8 |
* @const string
|
9 |
*/
|
10 |
-
const VERSION = '3.
|
11 |
|
12 |
/**
|
13 |
* WP-CLI command
|
@@ -83,14 +83,24 @@ class Plugin {
|
|
83 |
require_once $this->locations['inc_dir'] . 'functions.php';
|
84 |
|
85 |
// Load DB helper interface/class
|
86 |
-
$
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
89 |
}
|
90 |
|
|
|
91 |
if ( ! $this->db ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
wp_die(
|
93 |
-
|
94 |
esc_html__( 'Stream DB Error', 'stream' )
|
95 |
);
|
96 |
}
|
@@ -107,12 +117,15 @@ class Plugin {
|
|
107 |
// Add frontend indicator
|
108 |
add_action( 'wp_head', array( $this, 'frontend_indicator' ) );
|
109 |
|
|
|
|
|
|
|
110 |
// Load admin area classes
|
111 |
if ( is_admin() || ( defined( 'WP_STREAM_DEV_DEBUG' ) && WP_STREAM_DEV_DEBUG ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
112 |
$this->admin = new Admin( $this );
|
113 |
-
$this->install =
|
114 |
} elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
115 |
-
$this->admin = new Admin( $this );
|
116 |
}
|
117 |
|
118 |
// Load WP-CLI command
|
@@ -221,4 +234,17 @@ class Plugin {
|
|
221 |
public function get_version() {
|
222 |
return self::VERSION;
|
223 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 |
}
|
7 |
*
|
8 |
* @const string
|
9 |
*/
|
10 |
+
const VERSION = '3.2.0';
|
11 |
|
12 |
/**
|
13 |
* WP-CLI command
|
83 |
require_once $this->locations['inc_dir'] . 'functions.php';
|
84 |
|
85 |
// Load DB helper interface/class
|
86 |
+
$driver_class = apply_filters( 'wp_stream_db_driver', '\WP_Stream\DB_Driver_WPDB' );
|
87 |
+
$driver = null;
|
88 |
+
|
89 |
+
if ( class_exists( $driver_class ) ) {
|
90 |
+
$driver = new $driver_class();
|
91 |
+
$this->db = new DB( $driver );
|
92 |
}
|
93 |
|
94 |
+
$error = false;
|
95 |
if ( ! $this->db ) {
|
96 |
+
$error = esc_html__( 'Stream: Could not load chosen DB driver.', 'stream' );
|
97 |
+
} elseif ( ! $driver instanceof DB_Driver ) {
|
98 |
+
$error = esc_html__( 'Stream: DB driver must implement DB Driver interface.', 'stream' );
|
99 |
+
}
|
100 |
+
|
101 |
+
if ( $error ) {
|
102 |
wp_die(
|
103 |
+
esc_html( $error ),
|
104 |
esc_html__( 'Stream DB Error', 'stream' )
|
105 |
);
|
106 |
}
|
117 |
// Add frontend indicator
|
118 |
add_action( 'wp_head', array( $this, 'frontend_indicator' ) );
|
119 |
|
120 |
+
// Change DB driver after plugin loaded if any add-ons want to replace
|
121 |
+
add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ) );
|
122 |
+
|
123 |
// Load admin area classes
|
124 |
if ( is_admin() || ( defined( 'WP_STREAM_DEV_DEBUG' ) && WP_STREAM_DEV_DEBUG ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
125 |
$this->admin = new Admin( $this );
|
126 |
+
$this->install = $driver->setup_storage( $this );
|
127 |
} elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
128 |
+
$this->admin = new Admin( $this, $driver );
|
129 |
}
|
130 |
|
131 |
// Load WP-CLI command
|
234 |
public function get_version() {
|
235 |
return self::VERSION;
|
236 |
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Change plugin database driver in case driver plugin loaded after stream
|
240 |
+
*/
|
241 |
+
public function plugins_loaded() {
|
242 |
+
// Load DB helper interface/class
|
243 |
+
$driver_class = apply_filters( 'wp_stream_db_driver', '\WP_Stream\DB_Driver_WPDB' );
|
244 |
+
|
245 |
+
if ( class_exists( $driver_class ) ) {
|
246 |
+
$driver = new $driver_class();
|
247 |
+
$this->db = new DB( $driver );
|
248 |
+
}
|
249 |
+
}
|
250 |
}
|
classes/class-query.php
CHANGED
@@ -2,11 +2,6 @@
|
|
2 |
namespace WP_Stream;
|
3 |
|
4 |
class Query {
|
5 |
-
/**
|
6 |
-
* @var DB
|
7 |
-
*/
|
8 |
-
public $db;
|
9 |
-
|
10 |
/**
|
11 |
* Hold the number of records found
|
12 |
*
|
@@ -14,15 +9,6 @@ class Query {
|
|
14 |
*/
|
15 |
public $found_records = 0;
|
16 |
|
17 |
-
/**
|
18 |
-
* Class constructor.
|
19 |
-
*
|
20 |
-
* @param DB $db The parent database class.
|
21 |
-
*/
|
22 |
-
public function __construct( $db ) {
|
23 |
-
$this->db = $db;
|
24 |
-
}
|
25 |
-
|
26 |
/**
|
27 |
* Query records
|
28 |
*
|
@@ -33,70 +19,6 @@ class Query {
|
|
33 |
public function query( $args ) {
|
34 |
global $wpdb;
|
35 |
|
36 |
-
$defaults = array(
|
37 |
-
// Search param
|
38 |
-
'search' => null,
|
39 |
-
'search_field' => 'summary',
|
40 |
-
'record_after' => null, // Deprecated, use date_after instead
|
41 |
-
// Date-based filters
|
42 |
-
'date' => null, // Ex: 2015-07-01
|
43 |
-
'date_from' => null, // Ex: 2015-07-01
|
44 |
-
'date_to' => null, // Ex: 2015-07-01
|
45 |
-
'date_after' => null, // Ex: 2015-07-01T15:19:21+00:00
|
46 |
-
'date_before' => null, // Ex: 2015-07-01T15:19:21+00:00
|
47 |
-
// Record ID filters
|
48 |
-
'record' => null,
|
49 |
-
'record__in' => array(),
|
50 |
-
'record__not_in' => array(),
|
51 |
-
// Pagination params
|
52 |
-
'records_per_page' => get_option( 'posts_per_page', 20 ),
|
53 |
-
'paged' => 1,
|
54 |
-
// Order
|
55 |
-
'order' => 'desc',
|
56 |
-
'orderby' => 'date',
|
57 |
-
// Fields selection
|
58 |
-
'fields' => array(),
|
59 |
-
);
|
60 |
-
|
61 |
-
// Additional property fields
|
62 |
-
$properties = array(
|
63 |
-
'user_id' => null,
|
64 |
-
'user_role' => null,
|
65 |
-
'ip' => null,
|
66 |
-
'object_id' => null,
|
67 |
-
'site_id' => null,
|
68 |
-
'blog_id' => null,
|
69 |
-
'connector' => null,
|
70 |
-
'context' => null,
|
71 |
-
'action' => null,
|
72 |
-
);
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Filter allows additional query properties to be added
|
76 |
-
*
|
77 |
-
* @return array Array of query properties
|
78 |
-
*/
|
79 |
-
$properties = apply_filters( 'wp_stream_query_properties', $properties );
|
80 |
-
|
81 |
-
// Add property fields to defaults, including their __in/__not_in variations
|
82 |
-
foreach ( $properties as $property => $default ) {
|
83 |
-
if ( ! isset( $defaults[ $property ] ) ) {
|
84 |
-
$defaults[ $property ] = $default;
|
85 |
-
}
|
86 |
-
|
87 |
-
$defaults[ "{$property}__in" ] = array();
|
88 |
-
$defaults[ "{$property}__not_in" ] = array();
|
89 |
-
}
|
90 |
-
|
91 |
-
$args = wp_parse_args( $args, $defaults );
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Filter allows additional arguments to query $args
|
95 |
-
*
|
96 |
-
* @return array Array of query arguments
|
97 |
-
*/
|
98 |
-
$args = apply_filters( 'wp_stream_query_args', $args );
|
99 |
-
|
100 |
$join = '';
|
101 |
$where = '';
|
102 |
|
@@ -305,20 +227,19 @@ class Query {
|
|
305 |
*/
|
306 |
$query = apply_filters( 'wp_stream_db_query', $query, $args );
|
307 |
|
|
|
308 |
/**
|
309 |
* QUERY THE DATABASE FOR RESULTS
|
310 |
*/
|
311 |
-
$
|
312 |
-
|
313 |
-
// Hold the number of records found
|
314 |
-
$this->found_records = absint( $wpdb->get_var( 'SELECT FOUND_ROWS()' ) );
|
315 |
|
316 |
// Add meta to the records, when applicable
|
317 |
if ( empty( $fields ) || in_array( 'meta', $fields, true ) ) {
|
318 |
-
$
|
319 |
}
|
320 |
|
321 |
-
return
|
322 |
}
|
323 |
|
324 |
/**
|
2 |
namespace WP_Stream;
|
3 |
|
4 |
class Query {
|
|
|
|
|
|
|
|
|
|
|
5 |
/**
|
6 |
* Hold the number of records found
|
7 |
*
|
9 |
*/
|
10 |
public $found_records = 0;
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
/**
|
13 |
* Query records
|
14 |
*
|
19 |
public function query( $args ) {
|
20 |
global $wpdb;
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
$join = '';
|
23 |
$where = '';
|
24 |
|
227 |
*/
|
228 |
$query = apply_filters( 'wp_stream_db_query', $query, $args );
|
229 |
|
230 |
+
$result = array();
|
231 |
/**
|
232 |
* QUERY THE DATABASE FOR RESULTS
|
233 |
*/
|
234 |
+
$result['items'] = $wpdb->get_results( $query ); // @codingStandardsIgnoreLine $query already prepared
|
235 |
+
$result['count'] = $result['items'] ? absint( $wpdb->get_var( 'SELECT FOUND_ROWS()' ) ) : 0;
|
|
|
|
|
236 |
|
237 |
// Add meta to the records, when applicable
|
238 |
if ( empty( $fields ) || in_array( 'meta', $fields, true ) ) {
|
239 |
+
$result['items'] = $this->add_record_meta( $result['items'] );
|
240 |
}
|
241 |
|
242 |
+
return $result;
|
243 |
}
|
244 |
|
245 |
/**
|
classes/class-settings.php
CHANGED
@@ -84,7 +84,12 @@ class Settings {
|
|
84 |
'message' => esc_html__( 'There was an error in the request', 'stream' ),
|
85 |
);
|
86 |
|
87 |
-
$search =
|
|
|
|
|
|
|
|
|
|
|
88 |
|
89 |
$request = (object) array(
|
90 |
'find' => $search,
|
@@ -123,6 +128,7 @@ class Settings {
|
|
123 |
|
124 |
$response->status = true;
|
125 |
$response->message = '';
|
|
|
126 |
$response->users = array();
|
127 |
$users_added_to_response = array();
|
128 |
|
84 |
'message' => esc_html__( 'There was an error in the request', 'stream' ),
|
85 |
);
|
86 |
|
87 |
+
$search = '';
|
88 |
+
$input = wp_stream_filter_input( INPUT_POST, 'find' );
|
89 |
+
|
90 |
+
if ( ! isset( $input['term'] ) ) {
|
91 |
+
$search = wp_unslash( trim( $input['term'] ) );
|
92 |
+
}
|
93 |
|
94 |
$request = (object) array(
|
95 |
'find' => $search,
|
128 |
|
129 |
$response->status = true;
|
130 |
$response->message = '';
|
131 |
+
$response->roles = $this->get_roles();
|
132 |
$response->users = array();
|
133 |
$users_added_to_response = array();
|
134 |
|
connectors/class-connector-blogs.php
CHANGED
@@ -31,6 +31,13 @@ class Connector_Blogs extends Connector {
|
|
31 |
'update_blog_public',
|
32 |
);
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
/**
|
35 |
* Return translated connector label
|
36 |
*
|
31 |
'update_blog_public',
|
32 |
);
|
33 |
|
34 |
+
/**
|
35 |
+
* Register connector in the WP Frontend
|
36 |
+
*
|
37 |
+
* @var bool
|
38 |
+
*/
|
39 |
+
public $register_frontend = false;
|
40 |
+
|
41 |
/**
|
42 |
* Return translated connector label
|
43 |
*
|
connectors/class-connector-editor.php
CHANGED
@@ -23,6 +23,13 @@ class Connector_Editor extends Connector {
|
|
23 |
*/
|
24 |
private $edited_file = array();
|
25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
/**
|
27 |
* Register all context hooks
|
28 |
*
|
23 |
*/
|
24 |
private $edited_file = array();
|
25 |
|
26 |
+
/**
|
27 |
+
* Register connector in the WP Frontend
|
28 |
+
*
|
29 |
+
* @var bool
|
30 |
+
*/
|
31 |
+
public $register_frontend = false;
|
32 |
+
|
33 |
/**
|
34 |
* Register all context hooks
|
35 |
*
|
connectors/class-connector-installer.php
CHANGED
@@ -26,6 +26,13 @@ class Connector_Installer extends Connector {
|
|
26 |
'_core_updated_successfully',
|
27 |
);
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
/**
|
30 |
* Return translated connector label
|
31 |
*
|
26 |
'_core_updated_successfully',
|
27 |
);
|
28 |
|
29 |
+
/**
|
30 |
+
* Register connector in the WP Frontend
|
31 |
+
*
|
32 |
+
* @var bool
|
33 |
+
*/
|
34 |
+
public $register_frontend = false;
|
35 |
+
|
36 |
/**
|
37 |
* Return translated connector label
|
38 |
*
|
connectors/class-connector-jetpack.php
CHANGED
@@ -33,6 +33,13 @@ class Connector_Jetpack extends Connector {
|
|
33 |
'wp_ajax_jetpack_post_by_email_disable',
|
34 |
);
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
/**
|
37 |
* Tracked option keys
|
38 |
*
|
33 |
'wp_ajax_jetpack_post_by_email_disable',
|
34 |
);
|
35 |
|
36 |
+
/**
|
37 |
+
* Register connector in the WP Frontend
|
38 |
+
*
|
39 |
+
* @var bool
|
40 |
+
*/
|
41 |
+
public $register_frontend = false;
|
42 |
+
|
43 |
/**
|
44 |
* Tracked option keys
|
45 |
*
|
connectors/class-connector-menus.php
CHANGED
@@ -20,6 +20,13 @@ class Connector_Menus extends Connector {
|
|
20 |
'delete_nav_menu',
|
21 |
);
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
/**
|
24 |
* Return translated connector label
|
25 |
*
|
20 |
'delete_nav_menu',
|
21 |
);
|
22 |
|
23 |
+
/**
|
24 |
+
* Register connector in the WP Frontend
|
25 |
+
*
|
26 |
+
* @var bool
|
27 |
+
*/
|
28 |
+
public $register_frontend = false;
|
29 |
+
|
30 |
/**
|
31 |
* Return translated connector label
|
32 |
*
|
connectors/class-connector-posts.php
CHANGED
@@ -19,6 +19,13 @@ class Connector_Posts extends Connector {
|
|
19 |
'deleted_post',
|
20 |
);
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
/**
|
23 |
* Return translated connector label
|
24 |
*
|
19 |
'deleted_post',
|
20 |
);
|
21 |
|
22 |
+
/**
|
23 |
+
* Register connector in the WP Frontend
|
24 |
+
*
|
25 |
+
* @var bool
|
26 |
+
*/
|
27 |
+
public $register_frontend = false;
|
28 |
+
|
29 |
/**
|
30 |
* Return translated connector label
|
31 |
*
|
connectors/class-connector-settings.php
CHANGED
@@ -81,6 +81,13 @@ class Connector_Settings extends Connector {
|
|
81 |
'new_admin_email',
|
82 |
);
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
/**
|
85 |
* Register all context hooks
|
86 |
*
|
81 |
'new_admin_email',
|
82 |
);
|
83 |
|
84 |
+
/**
|
85 |
+
* Register connector in the WP Frontend
|
86 |
+
*
|
87 |
+
* @var bool
|
88 |
+
*/
|
89 |
+
public $register_frontend = false;
|
90 |
+
|
91 |
/**
|
92 |
* Register all context hooks
|
93 |
*
|
connectors/class-connector-taxonomies.php
CHANGED
@@ -35,6 +35,13 @@ class Connector_Taxonomies extends Connector {
|
|
35 |
*/
|
36 |
public $context_labels;
|
37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
/**
|
39 |
* Return translated connector label
|
40 |
*
|
35 |
*/
|
36 |
public $context_labels;
|
37 |
|
38 |
+
/**
|
39 |
+
* Register connector in the WP Frontend
|
40 |
+
*
|
41 |
+
* @var bool
|
42 |
+
*/
|
43 |
+
public $register_frontend = false;
|
44 |
+
|
45 |
/**
|
46 |
* Return translated connector label
|
47 |
*
|
includes/db-updates.php
CHANGED
@@ -60,31 +60,40 @@ function wp_stream_update_auto_300( $db_version, $current_version ) {
|
|
60 |
$plugin = wp_stream_get_instance();
|
61 |
$plugin->install->install( $current_version );
|
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 |
$wpdb->query( "DROP TABLE {$wpdb->base_prefix}stream_tmp, {$wpdb->base_prefix}stream_context_tmp" );
|
60 |
$plugin = wp_stream_get_instance();
|
61 |
$plugin->install->install( $current_version );
|
62 |
|
63 |
+
$starting_row = 0;
|
64 |
+
$rows_per_round = 5000;
|
65 |
|
66 |
+
$stream_entries = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->base_prefix}stream_tmp LIMIT %d, %d", $starting_row, $rows_per_round ) );
|
67 |
+
|
68 |
+
while ( ! empty( $stream_entries ) ) {
|
69 |
+
foreach ( $stream_entries as $entry ) {
|
70 |
+
$context = $wpdb->get_row(
|
71 |
+
$wpdb->prepare( "SELECT * FROM {$wpdb->base_prefix}stream_context_tmp WHERE record_id = %s LIMIT 1", $entry->ID )
|
72 |
+
);
|
73 |
+
|
74 |
+
$new_entry = array(
|
75 |
+
'site_id' => $entry->site_id,
|
76 |
+
'blog_id' => $entry->blog_id,
|
77 |
+
'user_id' => $entry->author,
|
78 |
+
'user_role' => $entry->author_role,
|
79 |
+
'summary' => $entry->summary,
|
80 |
+
'created' => $entry->created,
|
81 |
+
'connector' => $context->connector,
|
82 |
+
'context' => $context->context,
|
83 |
+
'action' => $context->action,
|
84 |
+
'ip' => $entry->ip,
|
85 |
+
);
|
86 |
+
|
87 |
+
if ( $entry->object_id && 0 !== $entry->object_id ) {
|
88 |
+
$new_entry['object_id'] = $entry->object_id;
|
89 |
+
}
|
90 |
+
|
91 |
+
$wpdb->insert( $wpdb->base_prefix . 'stream', $new_entry );
|
92 |
}
|
93 |
|
94 |
+
$starting_row += $rows_per_round;
|
95 |
+
|
96 |
+
$stream_entries = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->base_prefix}stream_tmp LIMIT %d, %d", $starting_row, $rows_per_round ) );
|
97 |
}
|
98 |
|
99 |
$wpdb->query( "DROP TABLE {$wpdb->base_prefix}stream_tmp, {$wpdb->base_prefix}stream_context_tmp" );
|
includes/functions.php
CHANGED
@@ -89,14 +89,16 @@ function wp_stream_json_encode( $data, $options = 0, $depth = 512 ) {
|
|
89 |
/**
|
90 |
* Return an array of sites for a network in a way that is also backwards compatible
|
91 |
*
|
|
|
|
|
92 |
* @return array
|
93 |
*/
|
94 |
-
function wp_stream_get_sites() {
|
95 |
if ( function_exists( 'get_sites' ) ) {
|
96 |
-
$sites = get_sites();
|
97 |
} else {
|
98 |
$sites = array();
|
99 |
-
foreach ( wp_get_sites() as $site ) {
|
100 |
$sites[] = WP_Site::get_instance( $site['blog_id'] );
|
101 |
}
|
102 |
}
|
89 |
/**
|
90 |
* Return an array of sites for a network in a way that is also backwards compatible
|
91 |
*
|
92 |
+
* @param string|array $args
|
93 |
+
*
|
94 |
* @return array
|
95 |
*/
|
96 |
+
function wp_stream_get_sites( $args = array() ) {
|
97 |
if ( function_exists( 'get_sites' ) ) {
|
98 |
+
$sites = get_sites( $args );
|
99 |
} else {
|
100 |
$sites = array();
|
101 |
+
foreach ( wp_get_sites( $args ) as $site ) {
|
102 |
$sites[] = WP_Site::get_instance( $site['blog_id'] );
|
103 |
}
|
104 |
}
|
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
Contributors: fjarrett, lukecarbis, stream, xwp
|
3 |
Tags: actions, activity, activity log, activity logs, admin actions, analytics, audit, audit log, audit logs, blackbox, black box, change, changes, dashboard, log, logs, stream, tracking, troubleshooting, wp stream
|
4 |
Requires at least: 3.9
|
5 |
-
Tested up to: 4.
|
6 |
-
Stable tag: 3.
|
7 |
License: GPLv2 or later
|
8 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -79,6 +79,16 @@ Thank you for wanting to make Stream better for everyone!
|
|
79 |
|
80 |
== Changelog ==
|
81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
= 3.1.1 - October 31, 2016 =
|
83 |
|
84 |
* Fix: Hotfix for Error Updating Stream DB.
|
2 |
Contributors: fjarrett, lukecarbis, stream, xwp
|
3 |
Tags: actions, activity, activity log, activity logs, admin actions, analytics, audit, audit log, audit logs, blackbox, black box, change, changes, dashboard, log, logs, stream, tracking, troubleshooting, wp stream
|
4 |
Requires at least: 3.9
|
5 |
+
Tested up to: 4.8
|
6 |
+
Stable tag: 3.2
|
7 |
License: GPLv2 or later
|
8 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
79 |
|
80 |
== Changelog ==
|
81 |
|
82 |
+
= 3.2.0 - March 15, 2017 =
|
83 |
+
|
84 |
+
* New: Stream now support alternate Database Drivers. ([#889](https://github.com/xwp/stream/pull/889))
|
85 |
+
* Fix: Exclude dropdown menus ([e5c8677](https://github.com/xwp/stream/commit/e5c8677), [3626ba8](https://github.com/xwp/stream/commit/3626ba8), [e923a92](https://github.com/xwp/stream/commit/e923a92))
|
86 |
+
* Fix: Prevent loading of connectors on frontend ([ed3a635](https://github.com/xwp/stream/commit/ed3a635))
|
87 |
+
* Fix: Customizer performance issue ([#898](https://github.com/xwp/stream/pull/898))
|
88 |
+
* Fix: Various Network Admin bugs ([#899](https://github.com/xwp/stream/pull/899))
|
89 |
+
* Tweak: Codeclimate & Editorconfig support ([#896](https://github.com/xwp/stream/pull/896))
|
90 |
+
* Tweak: Better DB migration support ([#905](https://github.com/xwp/stream/pull/905))
|
91 |
+
|
92 |
= 3.1.1 - October 31, 2016 =
|
93 |
|
94 |
* Fix: Hotfix for Error Updating Stream DB.
|
stream.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: Stream
|
4 |
* Plugin URI: https://wp-stream.com/
|
5 |
* Description: Stream tracks logged-in user activity so you can monitor every change made on your WordPress site in beautifully organized detail. All activity is organized by context, action and IP address for easy filtering. Developers can extend Stream with custom connectors to log any kind of action.
|
6 |
-
* Version: 3.
|
7 |
* Author: XWP
|
8 |
* Author URI: https://xwp.co/
|
9 |
* License: GPLv2+
|
3 |
* Plugin Name: Stream
|
4 |
* Plugin URI: https://wp-stream.com/
|
5 |
* Description: Stream tracks logged-in user activity so you can monitor every change made on your WordPress site in beautifully organized detail. All activity is organized by context, action and IP address for easy filtering. Developers can extend Stream with custom connectors to log any kind of action.
|
6 |
+
* Version: 3.2.0
|
7 |
* Author: XWP
|
8 |
* Author URI: https://xwp.co/
|
9 |
* License: GPLv2+
|
ui/css/admin.css
CHANGED
@@ -18,28 +18,33 @@
|
|
18 |
overflow: visible;
|
19 |
}
|
20 |
|
21 |
-
.post-type-wp_stream_alerts .select2 .select2-selection
|
|
|
22 |
border-color: #ccc;
|
23 |
background: #f7f7f7;
|
24 |
-webkit-box-shadow: 0 1px 0 #ccc;
|
25 |
box-shadow: 0 1px 0 #ccc;
|
26 |
}
|
27 |
|
28 |
-
.post-type-wp_stream_alerts .select2 .select2-selection--multiple
|
|
|
29 |
font-size: 0;
|
30 |
min-height: 28px;
|
31 |
}
|
32 |
|
33 |
-
.post-type-wp_stream_alerts .select2-container.select2-container--focus .select2-selection--multiple
|
|
|
34 |
border: solid #ccc 1px;
|
35 |
}
|
36 |
|
37 |
-
.post-type-wp_stream_alerts .select2-container .select2-selection--multiple .select2-selection__choice
|
|
|
38 |
margin-top: 4px;
|
39 |
margin-bottom: 3px;
|
40 |
}
|
41 |
|
42 |
-
.post-type-wp_stream_alerts .select2 .select2-selection .select2-selection__rendered
|
|
|
43 |
color: #555;
|
44 |
}
|
45 |
|
@@ -470,11 +475,16 @@
|
|
470 |
border: 1px solid rgba(160,0,0,0.75);
|
471 |
}
|
472 |
|
473 |
-
.
|
|
|
|
|
|
|
|
|
|
|
474 |
font-weight: bold;
|
475 |
}
|
476 |
|
477 |
-
.
|
478 |
padding-left: 8px;
|
479 |
}
|
480 |
|
18 |
overflow: visible;
|
19 |
}
|
20 |
|
21 |
+
.post-type-wp_stream_alerts .select2 .select2-selection,
|
22 |
+
.stream-exclude-list .select2 .select2-selection{
|
23 |
border-color: #ccc;
|
24 |
background: #f7f7f7;
|
25 |
-webkit-box-shadow: 0 1px 0 #ccc;
|
26 |
box-shadow: 0 1px 0 #ccc;
|
27 |
}
|
28 |
|
29 |
+
.post-type-wp_stream_alerts .select2 .select2-selection--multiple,
|
30 |
+
.stream-exclude-list .select2 .select2-selection--multiple{
|
31 |
font-size: 0;
|
32 |
min-height: 28px;
|
33 |
}
|
34 |
|
35 |
+
.post-type-wp_stream_alerts .select2-container.select2-container--focus .select2-selection--multiple,
|
36 |
+
.stream-exclude-list .select2-container.select2-container--focus .select2-selection--multiple{
|
37 |
border: solid #ccc 1px;
|
38 |
}
|
39 |
|
40 |
+
.post-type-wp_stream_alerts .select2-container .select2-selection--multiple .select2-selection__choice,
|
41 |
+
.stream-exclude-list .select2-container .select2-selection--multiple .select2-selection__choice{
|
42 |
margin-top: 4px;
|
43 |
margin-bottom: 3px;
|
44 |
}
|
45 |
|
46 |
+
.post-type-wp_stream_alerts .select2 .select2-selection .select2-selection__rendered,
|
47 |
+
.stream-exclude-list .select2 .select2-selection .select2-selection__rendered{
|
48 |
color: #555;
|
49 |
}
|
50 |
|
475 |
border: 1px solid rgba(160,0,0,0.75);
|
476 |
}
|
477 |
|
478 |
+
.stream-exclude-list .icon-users {
|
479 |
+
top: -3px !important;
|
480 |
+
position: relative !important;
|
481 |
+
}
|
482 |
+
|
483 |
+
.wp_stream_screen .select2-results__option .parent {
|
484 |
font-weight: bold;
|
485 |
}
|
486 |
|
487 |
+
.wp_stream_screen .select2-results__option .child {
|
488 |
padding-left: 8px;
|
489 |
}
|
490 |
|
ui/js/alerts.js
CHANGED
@@ -50,13 +50,12 @@ jQuery( function( $ ) {
|
|
50 |
|
51 |
return null;
|
52 |
}
|
53 |
-
}).change(function
|
54 |
var value = $( this ).val();
|
55 |
-
if (value) {
|
56 |
var parts = value.split( '-' );
|
57 |
$( this ).siblings( '.connector' ).val( parts[0] );
|
58 |
$( this ).siblings( '.context' ).val( parts[1] );
|
59 |
-
// $(this).removeAttr('name');
|
60 |
}
|
61 |
});
|
62 |
|
@@ -64,13 +63,13 @@ jQuery( function( $ ) {
|
|
64 |
$( el ).siblings( '.connector' ).val(),
|
65 |
$( el ).siblings( '.context' ).val()
|
66 |
];
|
67 |
-
if ('' === parts[1]) {
|
68 |
parts.splice( 1, 1 );
|
69 |
}
|
70 |
$( el ).val( parts.join( '-' ) ).trigger( 'change' );
|
71 |
});
|
72 |
|
73 |
-
$target.find( 'select.select2-select:not(.connector_or_context)' ).each(function
|
74 |
var element_id_split = $( this ).attr( 'id' ).split( '_' );
|
75 |
var select_name = element_id_split[element_id_split.length - 1].charAt( 0 ).toUpperCase() +
|
76 |
element_id_split[element_id_split.length - 1].slice( 1 );
|
@@ -169,14 +168,14 @@ jQuery( function( $ ) {
|
|
169 |
// Color taken from /wp-admin/css/forms.css
|
170 |
// #pass-strength-result.strong
|
171 |
add_new_alert.css( 'background-color', '#C1E1B9' );
|
172 |
-
setTimeout(function
|
173 |
add_new_alert.css( 'background-color', current_bg_color );
|
174 |
}, 250);
|
175 |
|
176 |
-
$( '#wp_stream_alert_type' ).change( function
|
177 |
loadAlertSettings( $( this ).val() );
|
178 |
});
|
179 |
-
add_new_alert.on( 'click', '.button-secondary.cancel', function
|
180 |
$( '#add-new-alert' ).remove();
|
181 |
});
|
182 |
add_new_alert.on( 'click', '.button-primary.save', save_new_alert );
|
50 |
|
51 |
return null;
|
52 |
}
|
53 |
+
}).change( function() {
|
54 |
var value = $( this ).val();
|
55 |
+
if ( value ) {
|
56 |
var parts = value.split( '-' );
|
57 |
$( this ).siblings( '.connector' ).val( parts[0] );
|
58 |
$( this ).siblings( '.context' ).val( parts[1] );
|
|
|
59 |
}
|
60 |
});
|
61 |
|
63 |
$( el ).siblings( '.connector' ).val(),
|
64 |
$( el ).siblings( '.context' ).val()
|
65 |
];
|
66 |
+
if ( '' === parts[1] ) {
|
67 |
parts.splice( 1, 1 );
|
68 |
}
|
69 |
$( el ).val( parts.join( '-' ) ).trigger( 'change' );
|
70 |
});
|
71 |
|
72 |
+
$target.find( 'select.select2-select:not(.connector_or_context)' ).each( function() {
|
73 |
var element_id_split = $( this ).attr( 'id' ).split( '_' );
|
74 |
var select_name = element_id_split[element_id_split.length - 1].charAt( 0 ).toUpperCase() +
|
75 |
element_id_split[element_id_split.length - 1].slice( 1 );
|
168 |
// Color taken from /wp-admin/css/forms.css
|
169 |
// #pass-strength-result.strong
|
170 |
add_new_alert.css( 'background-color', '#C1E1B9' );
|
171 |
+
setTimeout( function() {
|
172 |
add_new_alert.css( 'background-color', current_bg_color );
|
173 |
}, 250);
|
174 |
|
175 |
+
$( '#wp_stream_alert_type' ).change( function() {
|
176 |
loadAlertSettings( $( this ).val() );
|
177 |
});
|
178 |
+
add_new_alert.on( 'click', '.button-secondary.cancel', function() {
|
179 |
$( '#add-new-alert' ).remove();
|
180 |
});
|
181 |
add_new_alert.on( 'click', '.button-primary.save', save_new_alert );
|
ui/js/exclude.js
CHANGED
@@ -48,6 +48,14 @@ jQuery( function( $ ) {
|
|
48 |
|
49 |
return null;
|
50 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
});
|
52 |
});
|
53 |
|
@@ -76,38 +84,10 @@ jQuery( function( $ ) {
|
|
76 |
};
|
77 |
},
|
78 |
processResults: function( response ) {
|
79 |
-
var roles = [];
|
80 |
-
|
81 |
-
$( 'option', $input_user ).each( function() {
|
82 |
-
if ( $( this ).val() === '' ) {
|
83 |
-
return;
|
84 |
-
}
|
85 |
-
if ( ! $.isNumeric( $( this ).val() ) ) {
|
86 |
-
roles.push({
|
87 |
-
'id' : $( this ).val(),
|
88 |
-
'text' : $( this ).text()
|
89 |
-
});
|
90 |
-
}
|
91 |
-
});
|
92 |
-
|
93 |
-
roles = $.grep(
|
94 |
-
roles,
|
95 |
-
function( role ) {
|
96 |
-
var roleVal = $input_user.data( 'select2' ).dropdown.$search
|
97 |
-
.val()
|
98 |
-
.toLowerCase();
|
99 |
-
var rolePos = role
|
100 |
-
.text
|
101 |
-
.toLowerCase()
|
102 |
-
.indexOf( roleVal );
|
103 |
-
return rolePos >= 0;
|
104 |
-
}
|
105 |
-
);
|
106 |
-
|
107 |
var answer = {
|
108 |
results: [
|
109 |
{ text: '', id: '' },
|
110 |
-
{ text: 'Roles', children:
|
111 |
{ text: 'Users', children: [] }
|
112 |
]
|
113 |
};
|
@@ -116,15 +96,23 @@ jQuery( function( $ ) {
|
|
116 |
return answer;
|
117 |
}
|
118 |
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
});
|
124 |
|
|
|
125 |
answer.results[ 2 ].children = response.data.users;
|
126 |
|
127 |
-
//
|
128 |
return answer;
|
129 |
}
|
130 |
},
|
@@ -263,7 +251,8 @@ jQuery( function( $ ) {
|
|
263 |
initSettingsSelect2();
|
264 |
|
265 |
$( '.stream-exclude-list tr:not(.hidden) select.select2-select.author_or_role' ).each( function() {
|
266 |
-
$
|
|
|
267 |
});
|
268 |
|
269 |
$( '.stream-exclude-list tr:not(.hidden) select.select2-select.connector_or_context' ).each( function() {
|
@@ -342,6 +331,40 @@ jQuery( function( $ ) {
|
|
342 |
recalculate_rules_selected();
|
343 |
});
|
344 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
345 |
function recalculate_rules_selected() {
|
346 |
var $selectedRows = $( 'table.stream-exclude-list tbody tr:not( .hidden ) input.cb-select:checked' ),
|
347 |
$deleteButton = $( '#exclude_rules_remove_rules' );
|
48 |
|
49 |
return null;
|
50 |
}
|
51 |
+
}).on( 'change', function() {
|
52 |
+
var row = $( this ).closest( 'tr' ),
|
53 |
+
connector = $( this ).val();
|
54 |
+
if ( connector && 0 < connector.indexOf( '-' ) ) {
|
55 |
+
var connector_split = connector.split( '-' );
|
56 |
+
connector = connector_split[0];
|
57 |
+
}
|
58 |
+
getActions( row, connector );
|
59 |
});
|
60 |
});
|
61 |
|
84 |
};
|
85 |
},
|
86 |
processResults: function( response ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
var answer = {
|
88 |
results: [
|
89 |
{ text: '', id: '' },
|
90 |
+
{ text: 'Roles', children: [] },
|
91 |
{ text: 'Users', children: [] }
|
92 |
]
|
93 |
};
|
96 |
return answer;
|
97 |
}
|
98 |
|
99 |
+
if ( undefined === response.data.users || undefined === response.data.roles ) {
|
100 |
+
return answer;
|
101 |
+
}
|
102 |
+
|
103 |
+
var roles = [];
|
104 |
+
|
105 |
+
$.each( response.data.roles, function( id, text ) {
|
106 |
+
roles.push({
|
107 |
+
'id' : id,
|
108 |
+
'text' : text
|
109 |
+
});
|
110 |
});
|
111 |
|
112 |
+
answer.results[ 1 ].children = roles;
|
113 |
answer.results[ 2 ].children = response.data.users;
|
114 |
|
115 |
+
// Return the value of more so Select2 knows if more results can be loaded
|
116 |
return answer;
|
117 |
}
|
118 |
},
|
251 |
initSettingsSelect2();
|
252 |
|
253 |
$( '.stream-exclude-list tr:not(.hidden) select.select2-select.author_or_role' ).each( function() {
|
254 |
+
var $option = $('<option selected>' + $( this ).data( 'selected-text' ) + '</option>').val( $( this ).data( 'selected-id' ) );
|
255 |
+
$( this ).append( $option ).trigger( 'change' );
|
256 |
});
|
257 |
|
258 |
$( '.stream-exclude-list tr:not(.hidden) select.select2-select.connector_or_context' ).each( function() {
|
331 |
recalculate_rules_selected();
|
332 |
});
|
333 |
|
334 |
+
function getActions( row, connector ) {
|
335 |
+
var trigger_action = $( '.select2-select.action', row ),
|
336 |
+
action_value = trigger_action.val();
|
337 |
+
|
338 |
+
trigger_action.empty();
|
339 |
+
trigger_action.prop( 'disabled', true );
|
340 |
+
|
341 |
+
var placeholder = $( '<option/>', {value: '', text: ''} );
|
342 |
+
trigger_action.append( placeholder );
|
343 |
+
|
344 |
+
var data = {
|
345 |
+
'action' : 'get_actions',
|
346 |
+
'connector' : connector
|
347 |
+
};
|
348 |
+
|
349 |
+
$.post( window.ajaxurl, data, function( response ) {
|
350 |
+
var success = response.success,
|
351 |
+
actions = response.data;
|
352 |
+
if ( ! success ) {
|
353 |
+
return;
|
354 |
+
}
|
355 |
+
for ( var key in actions ) {
|
356 |
+
if ( actions.hasOwnProperty( key ) ) {
|
357 |
+
var value = actions[key];
|
358 |
+
var option = $( '<option/>', {value: key, text: value} );
|
359 |
+
trigger_action.append( option );
|
360 |
+
}
|
361 |
+
}
|
362 |
+
trigger_action.val( action_value );
|
363 |
+
trigger_action.prop( 'disabled', false );
|
364 |
+
$( document ).trigger( 'alert-actions-updated' );
|
365 |
+
});
|
366 |
+
}
|
367 |
+
|
368 |
function recalculate_rules_selected() {
|
369 |
var $selectedRows = $( 'table.stream-exclude-list tbody tr:not( .hidden ) input.cb-select:checked' ),
|
370 |
$deleteButton = $( '#exclude_rules_remove_rules' );
|