Version Description
- initial release
- more info
Download this release
Release Info
Developer | scribu |
Plugin | Posts 2 Posts |
Version | 0.1 |
Comparing to | |
See all releases |
Version 0.1
- admin.php +72 -0
- api.php +93 -0
- posts2posts.php +41 -0
- readme.txt +50 -0
- scb/Forms.php +366 -0
- scb/Util.php +162 -0
- 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 |
+
|