Posts 2 Posts - Version 0.1

Version Description

  • initial release
  • more info
Download this release

Release Info

Developer scribu
Plugin Icon wp plugin Posts 2 Posts
Version 0.1
Comparing to
See all releases

Version 0.1

Files changed (7) hide show
  1. admin.php +72 -0
  2. api.php +93 -0
  3. posts2posts.php +41 -0
  4. readme.txt +50 -0
  5. scb/Forms.php +366 -0
  6. scb/Util.php +162 -0
  7. scb/load.php +69 -0
admin.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class P2P_Box {
4
+
5
+ function init() {
6
+ add_action('add_meta_boxes', array(__CLASS__, 'register'));
7
+ add_action('save_post', array(__CLASS__, 'save'), 10, 2);
8
+ }
9
+
10
+ function save($post_a, $post) {
11
+ if ( defined('DOING_AJAX') || defined('DOING_CRON') || empty($_POST) || 'revision' == $post->post_type )
12
+ return;
13
+
14
+ $connections = p2p_get_connected('from', $post->ID);
15
+
16
+ foreach ( p2p_get_connection_types($post->post_type) as $post_type ) {
17
+ if ( !isset($_POST['p2p'][$post_type]) )
18
+ continue;
19
+
20
+ foreach ( $connections[$post_type] as $post_b )
21
+ p2p_disconnect($post_a, $post_b);
22
+
23
+ if ( $post_b = absint($_POST['p2p'][$post_type]) )
24
+ p2p_connect($post_a, $post_b);
25
+ }
26
+ }
27
+
28
+ function register($post_type) {
29
+ $connection_types = p2p_get_connection_types($post_type);
30
+
31
+ if ( empty($connection_types) )
32
+ return;
33
+
34
+ add_meta_box('p2p-connections', __('Connections', 'p2p-textdomain'), array(__CLASS__, 'box'), $post_type, 'side');
35
+ }
36
+
37
+ function box($post) {
38
+ $connections = p2p_get_connected('from', $post->ID);
39
+
40
+ $out = '';
41
+ foreach ( p2p_get_connection_types($post->post_type) as $post_type ) {
42
+ $posts = self::get_post_list($post_type);
43
+ $selected = reset(array_intersect((array) @$connections[$post_type], array_keys($posts)));
44
+
45
+ $out .=
46
+ html('li',
47
+ get_post_type_object($post_type)->singular_label . ' '
48
+ .scbForms::input(array(
49
+ 'type' => 'select',
50
+ 'name' => "p2p[$post_type]",
51
+ 'values' => self::get_post_list($post_type),
52
+ 'selected' => $selected,
53
+ ))
54
+ );
55
+ }
56
+
57
+ echo html('ul', $out);
58
+ }
59
+
60
+ private function get_post_list($post_type) {
61
+ $args = array(
62
+ 'post_type' => $post_type,
63
+ 'post_status' => 'any',
64
+ 'nopaging' => true,
65
+ 'cache_results' => false,
66
+ );
67
+
68
+ return scbUtil::objects_to_assoc(get_posts($args), 'ID', 'post_title');
69
+ }
70
+ }
71
+ P2P_Box::init();
72
+
api.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function p2p_register_connection_type($post_type_a, $post_type_b, $bydirectional = false) {
4
+ if ( !$ptype = get_post_type_object($post_type_a) )
5
+ return false;
6
+
7
+ $ptype->can_connect_to[] = $post_type_b;
8
+ $ptype->can_connect_to = array_unique($ptype->can_connect_to);
9
+
10
+ if ( $bydirectional && $post_type_a != $post_type_b )
11
+ p2p_register_connection_type($post_type_b, $post_type_a, false);
12
+
13
+ return true;
14
+ }
15
+
16
+ function p2p_get_connection_types($post_type_a) {
17
+ return (array) @get_post_type_object($post_type_a)->can_connect_to;
18
+ }
19
+
20
+
21
+ function p2p_connect($post_a, $post_b, $bydirectional = false) {
22
+ add_post_meta($post_a, P2P_META_KEY, $post_b, true);
23
+
24
+ if ( $bydirectional )
25
+ add_post_meta($post_b, P2P_META_KEY, $post_a, true);
26
+ }
27
+
28
+ function p2p_disconnect($post_a, $post_b, $bydirectional = false) {
29
+ delete_post_meta($post_a, P2P_META_KEY, $post_b);
30
+
31
+ if ( $bydirectional )
32
+ delete_post_meta($post_b, P2P_META_KEY, $post_a);
33
+ }
34
+
35
+ function p2p_is_connected($post_a, $post_b, $bydirectional = false) {
36
+ $r = (bool) get_post_meta($post_b, P2P_META_KEY, $post_a, true);
37
+
38
+ if ( $bydirectional )
39
+ $r = $r && p2p_is_connected($post_b, $post_a);
40
+
41
+ return $r;
42
+ }
43
+
44
+ function p2p_get_connected($direction, $post_id, $post_type = '') {
45
+ if ( 'to' == $direction ) {
46
+ $col_a = 'post_id';
47
+ $col_b = 'meta_value';
48
+ } else {
49
+ $col_b = 'post_id';
50
+ $col_a = 'meta_value';
51
+ }
52
+
53
+ $post_id = absint($post_id);
54
+
55
+ if ( !$post_id || (!empty($post_type) && !is_post_type($post_type)) )
56
+ return false;
57
+
58
+ global $wpdb;
59
+
60
+ if ( !empty($post_type) ) {
61
+ $query = $wpdb->prepare("
62
+ SELECT $col_a
63
+ FROM $wpdb->postmeta
64
+ WHERE meta_key = '" . P2P_META_KEY . "'
65
+ AND $col_b = $post_id
66
+ AND $col_a IN (
67
+ SELECT ID
68
+ FROM $wpdb->posts
69
+ WHERE post_type = %s
70
+ )
71
+ ", $post_type);
72
+
73
+ return $wpdb->get_col($query);
74
+ }
75
+
76
+ $query = "
77
+ SELECT $col_a AS post_id, (
78
+ SELECT post_type
79
+ FROM $wpdb->posts
80
+ WHERE $wpdb->posts.ID = $col_a
81
+ ) AS type
82
+ FROM $wpdb->postmeta
83
+ WHERE meta_key = '" . P2P_META_KEY . "'
84
+ AND $col_b = $post_id
85
+ ";
86
+
87
+ $connections = array();
88
+ foreach ( $wpdb->get_results($query) as $row )
89
+ $connections[$row->type][] = $row->post_id;
90
+
91
+ return $connections;
92
+ }
93
+
posts2posts.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Posts 2 Posts
4
+ Version: 0.1
5
+ Plugin Author: scribu
6
+ Description: Create connections between posts of different types
7
+ Author URI: http://scribu.net/
8
+ Plugin URI: http://scribu.net/wordpress/posts-to-posts
9
+ Text Domain: posts-to-posts
10
+ Domain Path: /lang
11
+
12
+
13
+ Copyright (C) 2010 scribu.net (scribu AT gmail DOT com)
14
+
15
+ This program is free software; you can redistribute it and/or modify
16
+ it under the terms of the GNU General Public License as published by
17
+ the Free Software Foundation; either version 3 of the License, or
18
+ (at your option) any later version.
19
+
20
+ This program is distributed in the hope that it will be useful,
21
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
+ GNU General Public License for more details.
24
+
25
+ You should have received a copy of the GNU General Public License
26
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
27
+ */
28
+
29
+ define('P2P_META_KEY', '_p2p');
30
+
31
+ function _p2p_init() {
32
+ require dirname(__FILE__) . '/scb/load.php';
33
+
34
+ require dirname(__FILE__) . '/api.php';
35
+
36
+ if ( is_admin() ) {
37
+ require dirname(__FILE__) . '/admin.php';
38
+ }
39
+ }
40
+ _p2p_init();
41
+
readme.txt ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Posts 2 Posts ===
2
+ Contributors: scribu
3
+ Donate link: http://scribu.net/paypal
4
+ Tags: cms, custom post types, relationships, graph, many-to-many
5
+ Requires at least: 3.0
6
+ Tested up to: 3.0
7
+ Stable tag: 0.1
8
+
9
+ Create connections between posts
10
+
11
+ == Description ==
12
+
13
+ This plugin allows you to create relationships between posts of different types. The relationships are stored in the postmeta table.
14
+
15
+ To register a connection type, write:
16
+
17
+ `
18
+ function my_connection_types() {
19
+ p2p_register_connection_type('book', 'author');
20
+ }
21
+ add_action('init', 'my_connection_types', 100);
22
+ `
23
+ <br>
24
+
25
+ See [available functions](http://plugins.trac.wordpress.org/browser/posts-to-posts/trunk/api.php).
26
+
27
+
28
+ == Installation ==
29
+
30
+ You can either install it automatically from the WordPress admin, or do it manually:
31
+
32
+ 1. Unzip the "Posts 2 Posts" archive and put the folder into your plugins folder (/wp-content/plugins/).
33
+ 1. Activate the plugin from the Plugins menu.
34
+
35
+ == Frequently Asked Questions ==
36
+
37
+ = Error on activation: "Parse error: syntax error, unexpected..." =
38
+
39
+ Make sure your host is running PHP 5. The only foolproof way to do this is to add this line to wp-config.php:
40
+
41
+ `var_dump(PHP_VERSION);`
42
+ <br>
43
+
44
+
45
+ == Changelog ==
46
+
47
+ = 0.1 =
48
+ * initial release
49
+ * [more info](http://scribu.net/wordpress/posts-to-posts/p2p-0-1.html)
50
+
scb/Forms.php ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Documentation: http://scribu.net/wordpress/scb-framework/scb-forms.html
4
+
5
+ class scbForms {
6
+
7
+ const token = '%input%';
8
+
9
+ protected static $args;
10
+ protected static $formdata = array();
11
+
12
+ static function input($args, $formdata = array()) {
13
+ $args = self::validate_data($args);
14
+
15
+ $error = false;
16
+ foreach ( array('name', 'value') as $key ) {
17
+ $old = $key . 's';
18
+
19
+ if ( isset($args[$old]) ) {
20
+ $args[$key] = $args[$old];
21
+ unset($args[$old]);
22
+ }
23
+ }
24
+
25
+ if ( empty($args['name']) )
26
+ return trigger_error('Empty name', E_USER_WARNING);
27
+
28
+ self::$args = $args;
29
+ self::$formdata = self::validate_data($formdata);
30
+
31
+ if ( 'select' == $args['type'] )
32
+ return self::_select();
33
+ else
34
+ return self::_input();
35
+ }
36
+
37
+
38
+ // Generates a form
39
+ static function form($inputs, $formdata = NULL, $nonce) {
40
+ $output = '';
41
+ foreach ( $inputs as $input )
42
+ $output .= self::input($input, $formdata);
43
+
44
+ $output = self::form_wrap($output, $nonce);
45
+
46
+ return $output;
47
+ }
48
+
49
+ // Wraps the given content in a <form> tag
50
+ static function form_wrap($content, $nonce = 'update_options') {
51
+ $output = "\n<form method='post' action=''>\n";
52
+ $output .= $content;
53
+ $output .= wp_nonce_field($action = $nonce, $name = "_wpnonce", $referer = true , $echo = false);
54
+ $output .= "\n</form>\n";
55
+
56
+ return $output;
57
+ }
58
+
59
+
60
+ // ____________PRIVATE METHODS____________
61
+
62
+
63
+ // Recursivly transform empty arrays to ''
64
+ private static function validate_data($data) {
65
+ if ( !is_array($data) )
66
+ return $data;
67
+
68
+ if ( empty($data) )
69
+ return '';
70
+
71
+ foreach ( $data as $key => &$value )
72
+ $value = self::validate_data($value);
73
+
74
+ return $data;
75
+ }
76
+
77
+ // From multiple inputs to single inputs
78
+ private static function _input() {
79
+ extract(wp_parse_args(self::$args, array(
80
+ 'name' => NULL,
81
+ 'value' => NULL,
82
+ 'desc' => NULL,
83
+ 'checked' => NULL,
84
+ )));
85
+
86
+ $m_name = is_array($name);
87
+ $m_value = is_array($value);
88
+ $m_desc = is_array($desc);
89
+
90
+ // Correct name
91
+ if ( !$m_name && $m_value
92
+ && 'checkbox' == $type
93
+ && false === strpos($name, '[')
94
+ )
95
+ $args['name'] = $name = $name . '[]';
96
+
97
+ // Expand names or values
98
+ if ( !$m_name && !$m_value ) {
99
+ $a = array($name => $value);
100
+ }
101
+ elseif ( $m_name && !$m_value ) {
102
+ $a = array_fill_keys($name, $value);
103
+ }
104
+ elseif ( !$m_name && $m_value ) {
105
+ $a = array_fill_keys($value, $name);
106
+ }
107
+ else {
108
+ $a = array_combine($name, $value);
109
+ }
110
+
111
+ // Correct descriptions
112
+ $_after = '';
113
+ if ( isset($desc) && !$m_desc && false === strpos($desc, self::token) ) {
114
+ if ( $m_value ) {
115
+ $_after = $desc;
116
+ $args['desc'] = $desc = $value;
117
+ }
118
+ elseif ( $m_name ) {
119
+ $_after = $desc;
120
+ $args['desc'] = $desc = $name;
121
+ }
122
+ }
123
+
124
+ // Determine what goes where
125
+ if ( !$m_name && $m_value ) {
126
+ $i1 = 'val';
127
+ $i2 = 'name';
128
+ } else {
129
+ $i1 = 'name';
130
+ $i2 = 'val';
131
+ }
132
+
133
+ $func = in_array($type, array('checkbox', 'radio')) ? '_checkbox_single' : '_input_single';
134
+
135
+ // Set constant args
136
+ $const_args = self::array_extract(self::$args, array('type', 'desc_pos', 'checked'));
137
+ if ( isset($extra) )
138
+ $const_args['extra'] = explode(' ', $extra);
139
+
140
+ $i = 0;
141
+ foreach ( $a as $name => $val ) {
142
+ $cur_args = $const_args;
143
+
144
+ if ( $$i1 !== NULL )
145
+ $cur_args['name'] = $$i1;
146
+
147
+ if ( $$i2 !== NULL )
148
+ $cur_args['value'] = $$i2;
149
+
150
+ // Set desc
151
+ if ( is_array($desc) )
152
+ $cur_args['desc'] = $desc[$i];
153
+ elseif ( isset($desc) )
154
+ $cur_args['desc'] = $desc;
155
+
156
+ // Find relevant formdata
157
+ $match = NULL;
158
+ if ( $checked === NULL ) {
159
+ $match = @self::$formdata[str_replace('[]', '', $$i1)];
160
+ if ( is_array($match) ) {
161
+ $match = $match[$i];
162
+ }
163
+ } else if ( is_array($checked) ) {
164
+ $cur_args['checked'] = isset($checked[$i]) && $checked[$i];
165
+ }
166
+
167
+ $output[] = self::$func($cur_args, $match);
168
+
169
+ $i++;
170
+ }
171
+
172
+ return implode("\n", $output) . $_after;
173
+ }
174
+
175
+ // Handle args for checkboxes and radio inputs
176
+ private static function _checkbox_single($args, $data) {
177
+ $args = wp_parse_args($args, array(
178
+ 'name' => NULL,
179
+ 'value' => true,
180
+ 'desc_pos' => 'after',
181
+ 'desc' => NULL,
182
+ 'checked' => NULL,
183
+ 'extra' => array(),
184
+ ));
185
+
186
+ foreach ( $args as $key => &$val )
187
+ $$key = &$val;
188
+ unset($val);
189
+
190
+ if ( $checked === NULL && $value == $data )
191
+ $checked = true;
192
+
193
+ if ( $checked )
194
+ $extra[] = 'checked="checked"';
195
+
196
+ if ( $desc === NULL && !is_bool($value) )
197
+ $desc = str_replace('[]', '', $value);
198
+
199
+ return self::_input_gen($args);
200
+ }
201
+
202
+ // Handle args for text inputs
203
+ private static function _input_single($args, $data) {
204
+ $args = wp_parse_args($args, array(
205
+ 'value' => $data,
206
+ 'desc_pos' => 'after',
207
+ 'extra' => array('class="regular-text"'),
208
+ ));
209
+
210
+ foreach ( $args as $key => &$val )
211
+ $$key = &$val;
212
+ unset($val);
213
+
214
+ if ( FALSE === strpos($name, '[') )
215
+ $extra[] = "id='{$name}'";
216
+
217
+ return self::_input_gen($args);
218
+ }
219
+
220
+ // Generate html with the final args
221
+ private static function _input_gen($args) {
222
+ extract(wp_parse_args($args, array(
223
+ 'name' => NULL,
224
+ 'value' => NULL,
225
+ 'desc' => NULL,
226
+ 'extra' => array()
227
+ )));
228
+
229
+ $extra = self::validate_extra($extra, $name);
230
+
231
+ if ( 'textarea' == $type ) {
232
+ $value = esc_html($value);
233
+ $input = "<textarea name='{$name}'{$extra}>\n{$value}\n</textarea>\n";
234
+ }
235
+ else {
236
+ $value = esc_attr($value);
237
+ $input = "<input name='{$name}' value='{$value}' type='{$type}'{$extra} /> ";
238
+ }
239
+
240
+ return self::add_label($input, $desc, $desc_pos);
241
+ }
242
+
243
+ private static function _select() {
244
+ extract(wp_parse_args(self::$args, array(
245
+ 'name' => '',
246
+ 'value' => array(),
247
+ 'text' => '',
248
+ 'selected' => array('foo'), // hack to make default blank
249
+ 'extra' => '',
250
+ 'numeric' => false, // use numeric array instead of associative
251
+ 'desc' => '',
252
+ 'desc_pos' => '',
253
+ )), EXTR_SKIP);
254
+
255
+ if ( empty($value) )
256
+ $value = array('' => '');
257
+
258
+ if ( !is_array($value) )
259
+ return trigger_error("'value' argument is expected to be an array", E_USER_WARNING);
260
+
261
+ if ( !self::is_associative($value) && !$numeric )
262
+ $value = array_combine($value, $value);
263
+
264
+ if ( isset(self::$formdata[$name]) )
265
+ $cur_val = self::$formdata[$name];
266
+ else
267
+ $cur_val = $selected;
268
+
269
+ if ( false === $text ) {
270
+ $opts = '';
271
+ } else {
272
+ $opts = "\t<option value=''";
273
+ if ( $cur_val === array('foo') )
274
+ $opts .= " selected='selected'";
275
+ $opts .= ">{$text}</option>\n";
276
+ }
277
+
278
+ foreach ( $value as $key => $value ) {
279
+ if ( empty($key) || empty($value) )
280
+ continue;
281
+
282
+ $cur_extra = array();
283
+ if ( (string) $key == (string) $cur_val )
284
+ $cur_extra[] = "selected='selected'";
285
+
286
+ $cur_extra = self::validate_extra($cur_extra, $key);
287
+
288
+ $opts .= "\t<option value='{$key}'{$cur_extra}>{$value}</option>\n";
289
+ }
290
+
291
+ $extra = self::validate_extra($extra, $name);
292
+
293
+ $input = "<select name='{$name}'$extra>\n{$opts}</select>";
294
+
295
+ return self::add_label($input, $desc, $desc_pos);
296
+ }
297
+
298
+ private static function add_label($input, $desc, $desc_pos) {
299
+ if ( empty($desc_pos) )
300
+ $desc_pos = 'after';
301
+
302
+ $label = '';
303
+ if ( false === strpos($desc, self::token) ) {
304
+ switch ($desc_pos) {
305
+ case 'before': $label = $desc . ' ' . self::token; break;
306
+ case 'after': $label = self::token . ' ' . $desc;
307
+ }
308
+ } else {
309
+ $label = $desc;
310
+ }
311
+
312
+ $label = trim(str_replace(self::token, $input, $label));
313
+
314
+ if ( empty($desc) )
315
+ $output = $input . "\n";
316
+ else
317
+ $output = "<label>{$label}</label>\n";
318
+
319
+ return $output;
320
+ }
321
+
322
+ private static function validate_extra($extra, $name, $implode = true) {
323
+ if ( !is_array($extra) )
324
+ $extra = explode(' ', $extra);
325
+
326
+ if ( empty($extra) )
327
+ return '';
328
+
329
+ return ' ' . ltrim(implode(' ', $extra));
330
+ }
331
+
332
+ // Utilities
333
+
334
+ private static function is_associative($array) {
335
+ if ( !is_array($array) || empty($array) )
336
+ return false;
337
+
338
+ $keys = array_keys($array);
339
+
340
+ return array_keys($keys) !== $keys;
341
+ }
342
+
343
+ private static function array_extract($array, $keys) {
344
+ $r = array();
345
+ foreach ( $keys as $key )
346
+ if ( isset($array[$key]) )
347
+ $r[$key] = $array[$key];
348
+
349
+ return $r;
350
+ }
351
+ }
352
+
353
+ // PHP < 5.2
354
+ if ( !function_exists('array_fill_keys') ) :
355
+ function array_fill_keys($keys, $value) {
356
+ if ( !is_array($keys) )
357
+ trigger_error('First argument is expected to be an array.' . gettype($keys) . 'given', E_USER_WARNING);
358
+
359
+ $r = array();
360
+ foreach ( $keys as $key )
361
+ $r[$key] = $value;
362
+
363
+ return $r;
364
+ }
365
+ endif;
366
+
scb/Util.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class scbUtil {
4
+
5
+ // Force script enqueue
6
+ static function do_scripts($handles) {
7
+ global $wp_scripts;
8
+
9
+ if ( ! is_a($wp_scripts, 'WP_Scripts') )
10
+ $wp_scripts = new WP_Scripts();
11
+
12
+ $wp_scripts->do_items((array) $handles);
13
+ }
14
+
15
+ // Force style enqueue
16
+ static function do_styles($handles) {
17
+ self::do_scripts('jquery');
18
+
19
+ global $wp_styles;
20
+
21
+ if ( ! is_a($wp_styles, 'WP_Styles') )
22
+ $wp_styles = new WP_Styles();
23
+
24
+ ob_start();
25
+ $wp_styles->do_items((array) $handles);
26
+ $content = str_replace(array('"', "\n"), array("'", ''), ob_get_clean());
27
+
28
+ echo "<script type='text/javascript'>\n";
29
+ echo "jQuery(document).ready(function($) {\n";
30
+ echo "$('head').prepend(\"$content\");\n";
31
+ echo "});\n";
32
+ echo "</script>";
33
+ }
34
+
35
+
36
+ // Have more than one uninstall hooks; also prevents an UPDATE query on each page load
37
+ static function add_uninstall_hook($plugin, $callback) {
38
+ register_uninstall_hook($plugin, '__return_false'); // dummy
39
+
40
+ add_action('uninstall_' . plugin_basename($plugin), $callback);
41
+ }
42
+
43
+ // Apply a function to each element of a (nested) array recursively
44
+ static function array_map_recursive($callback, $array) {
45
+ array_walk_recursive($array, array(__CLASS__, 'array_map_recursive_helper'), $callback);
46
+
47
+ return $array;
48
+ }
49
+
50
+ static function array_map_recursive_helper(&$val, $key, $callback) {
51
+ $val = call_user_func($callback, $val);
52
+ }
53
+
54
+ // Extract certain $keys from $array
55
+ static function array_extract($array, $keys) {
56
+ $r = array();
57
+
58
+ foreach ( $keys as $key )
59
+ if ( array_key_exists($key, $array) )
60
+ $r[$key] = $array[$key];
61
+
62
+ return $r;
63
+ }
64
+
65
+ // Extract a certain value from a list of arrays
66
+ static function array_pluck($array, $key) {
67
+ $r = array();
68
+
69
+ foreach ( $array as $value ) {
70
+ if ( is_object($value) )
71
+ $value = get_object_vars($value);
72
+ if ( array_key_exists($key, $value) )
73
+ $r[] = $value[$key];
74
+ }
75
+
76
+ return $r;
77
+ }
78
+
79
+ // Transform a list of objects into an associative array
80
+ static function objects_to_assoc($objects, $key, $value) {
81
+ $r = array();
82
+
83
+ foreach ( $objects as $obj )
84
+ $r[$obj->$key] = $obj->$value;
85
+
86
+ return $r;
87
+ }
88
+
89
+ // Prepare an array for an IN statement
90
+ static function array_to_sql($values) {
91
+ foreach ( $values as &$val )
92
+ $val = "'" . esc_sql(trim($val)) . "'";
93
+
94
+ return implode(',', $values);
95
+ }
96
+
97
+ // Example: split_at('</', '<a></a>') => array('<a>', '</a>')
98
+ static function split_at($delim, $str) {
99
+ $i = strpos($str, $delim);
100
+
101
+ if ( false === $i )
102
+ return false;
103
+
104
+ $start = substr($str, 0, $i);
105
+ $finish = substr($str, $i);
106
+
107
+ return array($start, $finish);
108
+ }
109
+ }
110
+
111
+
112
+ //_____Minimalist HTML framework_____
113
+
114
+
115
+ if ( ! function_exists('html') ):
116
+ function html($tag, $content = '') {
117
+ list($closing) = explode(' ', $tag, 2);
118
+
119
+ return "<{$tag}>{$content}</{$closing}>";
120
+ }
121
+ endif;
122
+
123
+ // Generate an <a> tag
124
+ if ( ! function_exists('html_link') ):
125
+ function html_link($url, $title = '') {
126
+ if ( empty($title) )
127
+ $title = $url;
128
+
129
+ return sprintf("<a href='%s'>%s</a>", esc_url($url), $title);
130
+ }
131
+ endif;
132
+
133
+
134
+ //_____Compatibility layer_____
135
+
136
+
137
+ // WP < 3.0
138
+ if ( ! function_exists('__return_false') ) :
139
+ function __return_false() {
140
+ return false;
141
+ }
142
+ endif;
143
+
144
+ // WP < ?
145
+ if ( ! function_exists('__return_true') ) :
146
+ function __return_true() {
147
+ return true;
148
+ }
149
+ endif;
150
+
151
+ // WP < ?
152
+ if ( ! function_exists('set_post_field') ) :
153
+ function set_post_field($field, $value, $post_id) {
154
+ global $wpdb;
155
+
156
+ $post_id = absint($post_id);
157
+ $value = sanitize_post_field($field, $value, $post_id, 'db');
158
+
159
+ return $wpdb->update($wpdb->posts, array($field => $value), array('ID' => $post_id));
160
+ }
161
+ endif;
162
+
scb/load.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( !class_exists('scbLoad3') ) :
3
+ class scbLoad3 {
4
+
5
+ private static $candidates;
6
+ private static $loaded;
7
+ private static $initial_load;
8
+
9
+ static function init($rev, $file, $classes) {
10
+ if ( $path = get_option('scb-framework') && !self::$initial_load ) {
11
+ if ( $path != __FILE__ )
12
+ include $path;
13
+
14
+ self::$initial_load = true;
15
+ }
16
+
17
+ self::$candidates[$file] = $rev;
18
+
19
+ self::load(dirname($file) . '/', $classes);
20
+
21
+ add_action('deactivate_plugin', array(__CLASS__, 'deactivate'));
22
+ add_action('update_option_active_plugins', array(__CLASS__, 'reorder'));
23
+ }
24
+
25
+ static function deactivate($plugin) {
26
+ $plugin = dirname($plugin);
27
+
28
+ if ( '.' == $plugin )
29
+ return;
30
+
31
+ foreach ( self::$candidates as $path => $rev )
32
+ if ( plugin_basename(dirname(dirname($path))) == $plugin )
33
+ unset(self::$candidates[$path]);
34
+ }
35
+
36
+ static function reorder() {
37
+ arsort(self::$candidates);
38
+
39
+ update_option('scb-framework', key(self::$candidates));
40
+ }
41
+
42
+ private static function load($path, $classes) {
43
+ foreach ( $classes as $class_name ) {
44
+ if ( class_exists($class_name) )
45
+ continue;
46
+
47
+ $fpath = $path . substr($class_name, 3) . '.php';
48
+
49
+ if ( file_exists($fpath) ) {
50
+ self::$loaded[$class_name] = $fpath;
51
+ include $fpath;
52
+ }
53
+ }
54
+ }
55
+
56
+ static function get_info() {
57
+ arsort(self::$candidates);
58
+
59
+ return array(get_option('scb-framework'), self::$loaded, self::$candidates);
60
+ }
61
+ }
62
+ endif;
63
+
64
+ scbLoad3::init(14, __FILE__, array(
65
+ 'scbUtil', 'scbOptions', 'scbForms', 'scbTable', 'scbDebug',
66
+ 'scbWidget', 'scbAdminPage', 'scbBoxesPage',
67
+ 'scbQuery', 'scbRewrite', 'scbCron',
68
+ ));
69
+