Version Description
- don't show metabox at all if user doesn't have the required capability
- fix checkbox handling when there are no other input fields
- improve metabox styling
- rename 'show_ui' to 'admin_box'
- add 'admin_column' parameter
Download this release
Release Info
Developer | scribu |
Plugin | Posts 2 Posts |
Version | 1.0.1 |
Comparing to | |
See all releases |
Code changes from version 0.9.5 to 1.0.1
- admin/base.php +0 -94
- admin/box-factory.php +179 -0
- admin/box.css +35 -15
- admin/box.js +20 -10
- admin/box.php +56 -90
- admin/column-factory.php +46 -0
- admin/column.php +40 -0
- admin/fields.php +15 -18
- admin/templates/box.html +36 -2
- admin/templates/create-connections.html +0 -15
- admin/templates/table-row.html +1 -3
- admin/templates/table.html +0 -13
- admin/utils.php +29 -0
- core/api.php +73 -17
- core/directed-type.php +86 -47
- core/ordered-type.php +27 -0
- core/query.php +4 -4
- core/storage.php +3 -0
- core/type.php +108 -76
- core/url-query.php +36 -0
- core/util.php +123 -0
- core/widget.php +36 -15
- lang/posts-to-posts-ro_RO.mo +0 -0
- lang/posts-to-posts-ro_RO.po +63 -43
- lang/posts-to-posts.pot +53 -33
- mustache/Mustache.php +36 -6
- mustache/MustacheLoader.php +85 -0
- posts-to-posts.php +16 -11
- readme.txt +23 -2
- scb/BoxesPage.php +5 -2
- scb/Forms.php +3 -2
- scb/load.php +1 -1
- screenshot-1.png +0 -0
- screenshot-2.png +0 -0
- screenshot-3.png +0 -0
- screenshot-4.png +0 -0
admin/base.php
DELETED
@@ -1,94 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
define( 'P2P_BOX_NONCE', 'p2p-box' );
|
4 |
-
|
5 |
-
/**
|
6 |
-
* @package Administration
|
7 |
-
*/
|
8 |
-
class P2P_Box_Factory {
|
9 |
-
|
10 |
-
function init() {
|
11 |
-
add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_boxes' ) );
|
12 |
-
add_action( 'save_post', array( __CLASS__, 'save_post' ), 10, 2 );
|
13 |
-
add_action( 'wp_ajax_p2p_box', array( __CLASS__, 'wp_ajax_p2p_box' ) );
|
14 |
-
}
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Add all the metaboxes.
|
18 |
-
*/
|
19 |
-
static function add_meta_boxes( $from ) {
|
20 |
-
foreach ( P2P_Connection_Type::get() as $ctype_id => $args ) {
|
21 |
-
$box = self::make_box( $ctype_id, $from );
|
22 |
-
if ( !$box )
|
23 |
-
continue;
|
24 |
-
|
25 |
-
$box->register();
|
26 |
-
}
|
27 |
-
}
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Collect metadata from all boxes.
|
31 |
-
*/
|
32 |
-
function save_post( $post_id, $post ) {
|
33 |
-
if ( 'revision' == $post->post_type || defined( 'DOING_AJAX' ) )
|
34 |
-
return;
|
35 |
-
|
36 |
-
// Custom fields
|
37 |
-
if ( isset( $_POST['p2p_meta'] ) ) {
|
38 |
-
foreach ( $_POST['p2p_meta'] as $p2p_id => $data ) {
|
39 |
-
foreach ( $data as $key => $value ) {
|
40 |
-
p2p_update_meta( $p2p_id, $key, $value );
|
41 |
-
}
|
42 |
-
}
|
43 |
-
}
|
44 |
-
|
45 |
-
// Ordering
|
46 |
-
if ( isset( $_POST['p2p_order'] ) ) {
|
47 |
-
foreach ( $_POST['p2p_order'] as $key => $list ) {
|
48 |
-
foreach ( $list as $i => $p2p_id ) {
|
49 |
-
p2p_update_meta( $p2p_id, $key, $i );
|
50 |
-
}
|
51 |
-
}
|
52 |
-
}
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Controller for all box ajax requests.
|
57 |
-
*/
|
58 |
-
function wp_ajax_p2p_box() {
|
59 |
-
check_ajax_referer( P2P_BOX_NONCE, 'nonce' );
|
60 |
-
|
61 |
-
$box = self::make_box( $_REQUEST['ctype_id'], $_REQUEST['post_type'] );
|
62 |
-
if ( !$box )
|
63 |
-
die(0);
|
64 |
-
|
65 |
-
if ( !current_user_can( $box->ptype->cap->edit_posts ) )
|
66 |
-
die(-1);
|
67 |
-
|
68 |
-
$method = 'ajax_' . $_REQUEST['subaction'];
|
69 |
-
|
70 |
-
$box->$method();
|
71 |
-
}
|
72 |
-
|
73 |
-
private static function make_box( $ctype_id, $post_type ) {
|
74 |
-
$ctype = p2p_type( $ctype_id );
|
75 |
-
|
76 |
-
if ( !$ctype )
|
77 |
-
return false;
|
78 |
-
|
79 |
-
if ( !$ctype->show_ui )
|
80 |
-
return false;
|
81 |
-
|
82 |
-
$directed = $ctype->find_direction( $post_type );
|
83 |
-
if ( !$directed )
|
84 |
-
return false;
|
85 |
-
|
86 |
-
if ( !$ctype->reciprocal && 'to' == $directed->direction )
|
87 |
-
return false;
|
88 |
-
|
89 |
-
return new P2P_Box( $directed, $post_type );
|
90 |
-
}
|
91 |
-
}
|
92 |
-
|
93 |
-
P2P_Box_Factory::init();
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
admin/box-factory.php
ADDED
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
define( 'P2P_BOX_NONCE', 'p2p-box' );
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @package Administration
|
7 |
+
*/
|
8 |
+
class P2P_Box_Factory {
|
9 |
+
|
10 |
+
private static $box_args = array();
|
11 |
+
|
12 |
+
static function register( $ctype_id, $box_args ) {
|
13 |
+
if ( isset( self::$box_args[$ctype_id] ) )
|
14 |
+
return false;
|
15 |
+
|
16 |
+
$box_args = (object) wp_parse_args( $box_args, array(
|
17 |
+
'show' => 'any',
|
18 |
+
'context' => 'side',
|
19 |
+
'fields' => array(),
|
20 |
+
'can_create_post' => true
|
21 |
+
) );
|
22 |
+
|
23 |
+
if ( !$box_args->show )
|
24 |
+
return false;
|
25 |
+
|
26 |
+
foreach ( $box_args->fields as &$field_args ) {
|
27 |
+
if ( !is_array( $field_args ) )
|
28 |
+
$field_args = array( 'title' => $field_args );
|
29 |
+
|
30 |
+
$field_args['type'] = _p2p_get_field_type( $field_args );
|
31 |
+
|
32 |
+
if ( 'checkbox' == $field_args['type'] && !isset( $field_args['values'] ) )
|
33 |
+
$field_args['values'] = array( true => ' ' );
|
34 |
+
}
|
35 |
+
|
36 |
+
self::$box_args[$ctype_id] = $box_args;
|
37 |
+
|
38 |
+
return true;
|
39 |
+
}
|
40 |
+
|
41 |
+
static function init() {
|
42 |
+
add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_boxes' ) );
|
43 |
+
add_action( 'save_post', array( __CLASS__, 'save_post' ), 10, 2 );
|
44 |
+
add_action( 'wp_ajax_p2p_box', array( __CLASS__, 'wp_ajax_p2p_box' ) );
|
45 |
+
}
|
46 |
+
|
47 |
+
static function add_meta_boxes( $post_type ) {
|
48 |
+
foreach ( self::$box_args as $ctype_id => $box_args ) {
|
49 |
+
$ctype = p2p_type( $ctype_id );
|
50 |
+
|
51 |
+
$dir = self::get_visible_directions( $post_type, $ctype, $box_args->show );
|
52 |
+
|
53 |
+
$title = $ctype->title;
|
54 |
+
|
55 |
+
if ( count( $dir ) > 1 && $title['from'] == $title['to'] ) {
|
56 |
+
$title['from'] .= __( ' (from)', P2P_TEXTDOMAIN );
|
57 |
+
$title['to'] .= __( ' (to)', P2P_TEXTDOMAIN );
|
58 |
+
}
|
59 |
+
|
60 |
+
foreach ( $dir as $direction ) {
|
61 |
+
$key = ( 'to' == $direction ) ? 'to' : 'from';
|
62 |
+
|
63 |
+
$directed = $ctype->set_direction( $direction );
|
64 |
+
|
65 |
+
$box = new P2P_Box( $box_args, $directed );
|
66 |
+
|
67 |
+
if ( !$box->check_capability() )
|
68 |
+
continue;
|
69 |
+
|
70 |
+
add_meta_box(
|
71 |
+
"p2p-{$direction}-{$ctype->id}",
|
72 |
+
$title[$key],
|
73 |
+
array( $box, 'render' ),
|
74 |
+
$post_type,
|
75 |
+
$box_args->context,
|
76 |
+
'default'
|
77 |
+
);
|
78 |
+
|
79 |
+
$box->init_scripts();
|
80 |
+
}
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
private static function get_visible_directions( $post_type, $ctype, $show_ui ) {
|
85 |
+
$direction = $ctype->find_direction( $post_type, false );
|
86 |
+
if ( !$direction )
|
87 |
+
return array();
|
88 |
+
|
89 |
+
if ( $ctype->indeterminate && !$ctype->reciprocal ) {
|
90 |
+
if ( 'any' == $show_ui )
|
91 |
+
return array( 'from', 'to' );
|
92 |
+
else
|
93 |
+
return array( $show_ui );
|
94 |
+
}
|
95 |
+
|
96 |
+
if ( 'any' == $show_ui || $direction == $show_ui )
|
97 |
+
return array( $direction );
|
98 |
+
|
99 |
+
return array();
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Collect metadata from all boxes.
|
104 |
+
*/
|
105 |
+
static function save_post( $post_id, $post ) {
|
106 |
+
if ( 'revision' == $post->post_type || defined( 'DOING_AJAX' ) )
|
107 |
+
return;
|
108 |
+
|
109 |
+
// Custom fields
|
110 |
+
if ( isset( $_POST['p2p_ctypes'] ) ) {
|
111 |
+
foreach ( $_POST['p2p_ctypes'] as $ctype_id ) {
|
112 |
+
$ctype = p2p_type( $ctype_id );
|
113 |
+
if ( !$ctype )
|
114 |
+
continue;
|
115 |
+
|
116 |
+
foreach ( $ctype->get_connected( $post_id )->posts as $post ) {
|
117 |
+
$p2p_id = $post->p2p_id;
|
118 |
+
$data = scbForms::get_value( array( 'p2p_meta', $p2p_id ), $_POST, array() );
|
119 |
+
|
120 |
+
foreach ( self::$box_args[$ctype_id]->fields as $key => $field_args ) {
|
121 |
+
if ( 'checkbox' == $field_args['type'] ) {
|
122 |
+
$new_values = scbForms::get_value( $key, $data, array() );
|
123 |
+
|
124 |
+
$old_values = p2p_get_meta( $p2p_id, $key );
|
125 |
+
|
126 |
+
foreach ( array_diff( $new_values, $old_values ) as $value )
|
127 |
+
p2p_add_meta( $p2p_id, $key, $value );
|
128 |
+
|
129 |
+
foreach ( array_diff( $old_values, $new_values ) as $value )
|
130 |
+
p2p_delete_meta( $p2p_id, $key, $value );
|
131 |
+
} else {
|
132 |
+
p2p_update_meta( $p2p_id, $key, $data[$key] );
|
133 |
+
}
|
134 |
+
}
|
135 |
+
}
|
136 |
+
}
|
137 |
+
}
|
138 |
+
|
139 |
+
// Ordering
|
140 |
+
if ( isset( $_POST['p2p_order'] ) ) {
|
141 |
+
foreach ( $_POST['p2p_order'] as $key => $list ) {
|
142 |
+
foreach ( $list as $i => $p2p_id ) {
|
143 |
+
p2p_update_meta( $p2p_id, $key, $i );
|
144 |
+
}
|
145 |
+
}
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Controller for all box ajax requests.
|
151 |
+
*/
|
152 |
+
static function wp_ajax_p2p_box() {
|
153 |
+
check_ajax_referer( P2P_BOX_NONCE, 'nonce' );
|
154 |
+
|
155 |
+
$ctype = p2p_type( $_REQUEST['ctype_id'] );
|
156 |
+
if ( !$ctype || !isset( self::$box_args[$ctype->id] ) )
|
157 |
+
die(0);
|
158 |
+
|
159 |
+
$post_type = get_post_type( $_REQUEST['from'] );
|
160 |
+
if ( !$post_type )
|
161 |
+
die(0);
|
162 |
+
|
163 |
+
$directed = $ctype->set_direction( $_REQUEST['direction'] );
|
164 |
+
if ( !$directed )
|
165 |
+
die(0);
|
166 |
+
|
167 |
+
$box = new P2P_Box( self::$box_args[$ctype->id], $directed, $post_type );
|
168 |
+
|
169 |
+
if ( !$box->check_capability() )
|
170 |
+
die(-1);
|
171 |
+
|
172 |
+
$method = 'ajax_' . $_REQUEST['subaction'];
|
173 |
+
|
174 |
+
$box->$method();
|
175 |
+
}
|
176 |
+
}
|
177 |
+
|
178 |
+
P2P_Box_Factory::init();
|
179 |
+
|
admin/box.css
CHANGED
@@ -6,6 +6,10 @@
|
|
6 |
margin-bottom: 8px;
|
7 |
}
|
8 |
|
|
|
|
|
|
|
|
|
9 |
/* Tabs */
|
10 |
|
11 |
.p2p-box .tabs-panel {
|
@@ -50,8 +54,7 @@
|
|
50 |
.p2p-connections th,
|
51 |
.p2p-connections td,
|
52 |
.p2p-results td {
|
53 |
-
padding
|
54 |
-
padding-right: 6px;
|
55 |
}
|
56 |
|
57 |
th.p2p-col-delete,
|
@@ -68,10 +71,6 @@ td.p2p-col-create {
|
|
68 |
vertical-align: middle;
|
69 |
}
|
70 |
|
71 |
-
th.p2p-col-delete a {
|
72 |
-
padding-bottom: 8px;
|
73 |
-
}
|
74 |
-
|
75 |
.p2p-results tr:first-child td {
|
76 |
border-top: 0;
|
77 |
}
|
@@ -94,17 +93,28 @@ th.p2p-col-delete a {
|
|
94 |
.p2p-col-delete a {
|
95 |
display: block;
|
96 |
height: 16px;
|
97 |
-
margin-top: 1px;
|
98 |
-
opacity: 0.5;
|
99 |
width: 16px;
|
100 |
}
|
101 |
|
102 |
-
.p2p-col-create
|
103 |
-
.p2p-col-delete
|
|
|
|
|
|
|
|
|
|
|
104 |
background-color: #f5f5f5;
|
105 |
-
border-right:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
opacity: 1;
|
107 |
-
width: 15px;
|
108 |
}
|
109 |
|
110 |
.p2p-col-create a {
|
@@ -115,6 +125,10 @@ th.p2p-col-delete a {
|
|
115 |
background: url("images/delete.png") no-repeat scroll 50% 50% transparent;
|
116 |
}
|
117 |
|
|
|
|
|
|
|
|
|
118 |
tr:hover td.p2p-col-order {
|
119 |
cursor: move;
|
120 |
background: url("images/sort.png") no-repeat scroll 50% 50% transparent;
|
@@ -170,6 +184,7 @@ tr:hover td.p2p-col-order {
|
|
170 |
margin-top: 3px;
|
171 |
}
|
172 |
|
|
|
173 |
/* RTL support */
|
174 |
|
175 |
body.rtl .p2p-navigation div {
|
@@ -186,12 +201,17 @@ body.rtl .p2p-tab-search input {
|
|
186 |
padding-right: 0;
|
187 |
}
|
188 |
|
189 |
-
body.rtl .p2p-col-create
|
190 |
-
body.rtl .p2p-col-delete
|
191 |
-
border-left: 1px solid
|
192 |
border-right: 0;
|
193 |
}
|
194 |
|
|
|
|
|
|
|
|
|
|
|
195 |
body.rtl .p2p-navigation div {
|
196 |
margin-right: 0;
|
197 |
margin-left: 5px;
|
6 |
margin-bottom: 8px;
|
7 |
}
|
8 |
|
9 |
+
.p2p-connections a {
|
10 |
+
text-decoration: none;
|
11 |
+
}
|
12 |
+
|
13 |
/* Tabs */
|
14 |
|
15 |
.p2p-box .tabs-panel {
|
54 |
.p2p-connections th,
|
55 |
.p2p-connections td,
|
56 |
.p2p-results td {
|
57 |
+
padding: 3px 6px;
|
|
|
58 |
}
|
59 |
|
60 |
th.p2p-col-delete,
|
71 |
vertical-align: middle;
|
72 |
}
|
73 |
|
|
|
|
|
|
|
|
|
74 |
.p2p-results tr:first-child td {
|
75 |
border-top: 0;
|
76 |
}
|
93 |
.p2p-col-delete a {
|
94 |
display: block;
|
95 |
height: 16px;
|
|
|
|
|
96 |
width: 16px;
|
97 |
}
|
98 |
|
99 |
+
.p2p-col-create,
|
100 |
+
.p2p-col-delete {
|
101 |
+
border-right: 1px solid transparent;
|
102 |
+
}
|
103 |
+
|
104 |
+
.p2p-col-create:hover,
|
105 |
+
.p2p-col-delete:hover {
|
106 |
background-color: #f5f5f5;
|
107 |
+
border-right-color: #ddd;
|
108 |
+
}
|
109 |
+
|
110 |
+
.p2p-col-create a,
|
111 |
+
.p2p-col-delete a {
|
112 |
+
opacity: 0.5;
|
113 |
+
}
|
114 |
+
|
115 |
+
.p2p-col-create:hover a,
|
116 |
+
.p2p-col-delete:hover a {
|
117 |
opacity: 1;
|
|
|
118 |
}
|
119 |
|
120 |
.p2p-col-create a {
|
125 |
background: url("images/delete.png") no-repeat scroll 50% 50% transparent;
|
126 |
}
|
127 |
|
128 |
+
td.p2p-col-order {
|
129 |
+
width: 13px;
|
130 |
+
}
|
131 |
+
|
132 |
tr:hover td.p2p-col-order {
|
133 |
cursor: move;
|
134 |
background: url("images/sort.png") no-repeat scroll 50% 50% transparent;
|
184 |
margin-top: 3px;
|
185 |
}
|
186 |
|
187 |
+
|
188 |
/* RTL support */
|
189 |
|
190 |
body.rtl .p2p-navigation div {
|
201 |
padding-right: 0;
|
202 |
}
|
203 |
|
204 |
+
body.rtl .p2p-col-create,
|
205 |
+
body.rtl .p2p-col-delete {
|
206 |
+
border-left: 1px solid transparent;
|
207 |
border-right: 0;
|
208 |
}
|
209 |
|
210 |
+
body.rtl .p2p-col-create:hover,
|
211 |
+
body.rtl .p2p-col-delete:hover {
|
212 |
+
border-left-color: #ddd;
|
213 |
+
}
|
214 |
+
|
215 |
body.rtl .p2p-navigation div {
|
216 |
margin-right: 0;
|
217 |
margin-left: 5px;
|
admin/box.js
CHANGED
@@ -28,13 +28,19 @@
|
|
28 |
'src': P2PAdmin.spinner,
|
29 |
'class': 'p2p-spinner'
|
30 |
});
|
31 |
-
ajax_request = function(data, callback,
|
32 |
-
|
33 |
data.action = 'p2p_box';
|
34 |
data.nonce = P2PAdmin.nonce;
|
35 |
data.ctype_id = $metabox.data('ctype_id');
|
36 |
-
data.
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
};
|
39 |
row_ajax_request = function($td, data, callback){
|
40 |
$td.html($spinner.show());
|
@@ -54,8 +60,7 @@
|
|
54 |
$self = jQuery(ev.target);
|
55 |
$td = $self.closest('td');
|
56 |
data = {
|
57 |
-
subaction: 'clear_connections'
|
58 |
-
post_id: jQuery('#post_ID').val()
|
59 |
};
|
60 |
row_ajax_request($td, data, function(response){
|
61 |
$connections.hide().find('tbody').html('');
|
@@ -87,7 +92,6 @@
|
|
87 |
$td = $self.closest('td');
|
88 |
data = {
|
89 |
subaction: 'connect',
|
90 |
-
from: jQuery('#post_ID').val(),
|
91 |
to: $self.data('post_id')
|
92 |
};
|
93 |
row_ajax_request($td, data, function(response){
|
@@ -137,7 +141,6 @@
|
|
137 |
this.tab.delegate('.p2p-prev, .p2p-next', 'click', __bind(this, this.change_page));
|
138 |
this.data = {
|
139 |
subaction: 'search',
|
140 |
-
post_id: jQuery('#post_ID').val(),
|
141 |
s: ''
|
142 |
};
|
143 |
}
|
@@ -165,10 +168,18 @@
|
|
165 |
? new_page > this.total_pages ? this.current_page : new_page
|
166 |
: this.current_page;
|
167 |
$spinner.appendTo(this.tab.find('.p2p-navigation'));
|
168 |
-
return ajax_request(this.data, __bind(this, this.update_rows), '
|
169 |
};
|
170 |
prototype.update_rows = function(response){
|
171 |
$spinner.remove();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
this.tab.find('.p2p-results, .p2p-navigation, .p2p-notice').remove();
|
173 |
if (!response.rows) {
|
174 |
return this.tab.append(jQuery('<div class="p2p-notice">').html(response.msg));
|
@@ -218,7 +229,6 @@
|
|
218 |
$button.addClass('inactive');
|
219 |
data = {
|
220 |
subaction: 'create_post',
|
221 |
-
from: jQuery('#post_ID').val(),
|
222 |
post_title: title
|
223 |
};
|
224 |
ajax_request(data, function(response){
|
28 |
'src': P2PAdmin.spinner,
|
29 |
'class': 'p2p-spinner'
|
30 |
});
|
31 |
+
ajax_request = function(data, callback, type){
|
32 |
+
type == null && (type = 'POST');
|
33 |
data.action = 'p2p_box';
|
34 |
data.nonce = P2PAdmin.nonce;
|
35 |
data.ctype_id = $metabox.data('ctype_id');
|
36 |
+
data.direction = $metabox.data('direction');
|
37 |
+
data.from = jQuery('#post_ID').val();
|
38 |
+
return jQuery.ajax({
|
39 |
+
type: type,
|
40 |
+
url: ajaxurl,
|
41 |
+
data: data,
|
42 |
+
success: callback
|
43 |
+
});
|
44 |
};
|
45 |
row_ajax_request = function($td, data, callback){
|
46 |
$td.html($spinner.show());
|
60 |
$self = jQuery(ev.target);
|
61 |
$td = $self.closest('td');
|
62 |
data = {
|
63 |
+
subaction: 'clear_connections'
|
|
|
64 |
};
|
65 |
row_ajax_request($td, data, function(response){
|
66 |
$connections.hide().find('tbody').html('');
|
92 |
$td = $self.closest('td');
|
93 |
data = {
|
94 |
subaction: 'connect',
|
|
|
95 |
to: $self.data('post_id')
|
96 |
};
|
97 |
row_ajax_request($td, data, function(response){
|
141 |
this.tab.delegate('.p2p-prev, .p2p-next', 'click', __bind(this, this.change_page));
|
142 |
this.data = {
|
143 |
subaction: 'search',
|
|
|
144 |
s: ''
|
145 |
};
|
146 |
}
|
168 |
? new_page > this.total_pages ? this.current_page : new_page
|
169 |
: this.current_page;
|
170 |
$spinner.appendTo(this.tab.find('.p2p-navigation'));
|
171 |
+
return ajax_request(this.data, __bind(this, this.update_rows), 'GET');
|
172 |
};
|
173 |
prototype.update_rows = function(response){
|
174 |
$spinner.remove();
|
175 |
+
try {
|
176 |
+
response = jQuery.parseJSON(response);
|
177 |
+
} catch (e) {
|
178 |
+
if (typeof console != 'undefined' && console !== null) {
|
179 |
+
console.error('Malformed response', response);
|
180 |
+
}
|
181 |
+
return;
|
182 |
+
}
|
183 |
this.tab.find('.p2p-results, .p2p-navigation, .p2p-notice').remove();
|
184 |
if (!response.rows) {
|
185 |
return this.tab.append(jQuery('<div class="p2p-notice">').html(response.msg));
|
229 |
$button.addClass('inactive');
|
230 |
data = {
|
231 |
subaction: 'create_post',
|
|
|
232 |
post_title: title
|
233 |
};
|
234 |
ajax_request(data, function(response){
|
admin/box.php
CHANGED
@@ -14,9 +14,9 @@ interface P2P_Field {
|
|
14 |
class P2P_Box {
|
15 |
private $ctype;
|
16 |
|
17 |
-
private $
|
18 |
|
19 |
-
|
20 |
|
21 |
private $columns;
|
22 |
|
@@ -26,42 +26,19 @@ class P2P_Box {
|
|
26 |
'post_status' => 'any',
|
27 |
);
|
28 |
|
29 |
-
function __construct( $
|
30 |
-
$this->
|
31 |
-
|
32 |
-
$this->current_ptype = $current_ptype;
|
33 |
|
34 |
-
$
|
35 |
-
$this->ptype = get_post_type_object( $other_ptype[0] );
|
36 |
|
37 |
-
|
38 |
-
require dirname(__FILE__) . '/../mustache/Mustache.php';
|
39 |
|
40 |
add_filter( 'posts_search', array( __CLASS__, '_search_by_title' ), 10, 2 );
|
41 |
|
42 |
$this->init_columns();
|
43 |
}
|
44 |
|
45 |
-
public function
|
46 |
-
$title = $this->ctype->get_title();
|
47 |
-
|
48 |
-
if ( empty( $title ) ) {
|
49 |
-
$title = sprintf( __( 'Connected %s', P2P_TEXTDOMAIN ), $this->ptype->labels->name );
|
50 |
-
}
|
51 |
-
|
52 |
-
add_meta_box(
|
53 |
-
'p2p-connections-' . $this->ctype->id,
|
54 |
-
$title,
|
55 |
-
array( $this, 'render' ),
|
56 |
-
$this->current_ptype,
|
57 |
-
$this->ctype->context,
|
58 |
-
'default'
|
59 |
-
);
|
60 |
-
|
61 |
-
$this->init_scripts();
|
62 |
-
}
|
63 |
-
|
64 |
-
protected function init_scripts() {
|
65 |
wp_enqueue_style( 'p2p-admin', plugins_url( 'box.css', __FILE__ ), array(), P2P_PLUGIN_VERSION );
|
66 |
|
67 |
wp_enqueue_script( 'p2p-admin', plugins_url( 'box.js', __FILE__ ), array( 'jquery' ), P2P_PLUGIN_VERSION, true );
|
@@ -78,12 +55,12 @@ class P2P_Box {
|
|
78 |
'title' => new P2P_Field_Title( $this->ptype->labels->singular_name ),
|
79 |
);
|
80 |
|
81 |
-
foreach ( $this->
|
82 |
$this->columns[ $key ] = new P2P_Field_Generic( $data );
|
83 |
}
|
84 |
|
85 |
-
if ( $this->ctype
|
86 |
-
$this->columns['order'] = new P2P_Field_Order( $this->ctype->
|
87 |
}
|
88 |
}
|
89 |
|
@@ -94,23 +71,28 @@ class P2P_Box {
|
|
94 |
$this->connected_posts = $this->ctype->get_connected( $post->ID, $qv )->posts;
|
95 |
|
96 |
$data = array(
|
|
|
|
|
97 |
'connections' => $this->render_connections_table( $post ),
|
98 |
-
'create-connections' => $this->render_create_connections( $post )
|
99 |
);
|
100 |
|
|
|
|
|
|
|
|
|
101 |
$data_attr = array(
|
102 |
'ctype_id' => $this->ctype->id,
|
103 |
'prevent_duplicates' => $this->ctype->prevent_duplicates,
|
104 |
-
'cardinality' => $this->ctype->
|
|
|
105 |
);
|
106 |
|
107 |
$data_attr_str = array();
|
108 |
foreach ( $data_attr as $key => $value )
|
109 |
$data_attr_str[] = "data-$key='" . $value . "'";
|
110 |
|
111 |
-
|
112 |
-
|
113 |
-
echo _p2p_mustache_render( 'box.html', $data );
|
114 |
}
|
115 |
|
116 |
protected function render_connections_table( $post ) {
|
@@ -119,9 +101,9 @@ class P2P_Box {
|
|
119 |
if ( empty( $this->connected_posts ) )
|
120 |
$data['hide'] = 'style="display:none"';
|
121 |
|
122 |
-
$tbody =
|
123 |
foreach ( $this->connected_posts as $connected ) {
|
124 |
-
$tbody
|
125 |
}
|
126 |
$data['tbody'] = $tbody;
|
127 |
|
@@ -132,19 +114,19 @@ class P2P_Box {
|
|
132 |
);
|
133 |
}
|
134 |
|
135 |
-
return
|
136 |
}
|
137 |
|
138 |
protected function render_create_connections( $post ) {
|
139 |
$data = array(
|
140 |
-
'
|
141 |
);
|
142 |
|
143 |
-
if (
|
144 |
$data['hide'] = 'style="display:none"';
|
145 |
|
146 |
// Search tab
|
147 |
-
$tab_content =
|
148 |
'placeholder' => $this->ptype->labels->search_items,
|
149 |
) );
|
150 |
|
@@ -164,7 +146,7 @@ class P2P_Box {
|
|
164 |
|
165 |
// Create post tab
|
166 |
if ( $this->can_create_post() ) {
|
167 |
-
$tab_content =
|
168 |
'title' => $this->ptype->labels->add_new_item
|
169 |
) );
|
170 |
|
@@ -175,20 +157,27 @@ class P2P_Box {
|
|
175 |
);
|
176 |
}
|
177 |
|
178 |
-
return
|
|
|
|
|
|
|
|
|
179 |
}
|
180 |
|
181 |
-
protected function
|
182 |
$data = array();
|
183 |
|
184 |
-
foreach ( $
|
185 |
$data['columns'][] = array(
|
186 |
'column' => $key,
|
187 |
'content' => $field->render( $key, $p2p_id, $post_id )
|
188 |
);
|
189 |
}
|
190 |
|
191 |
-
|
|
|
|
|
|
|
192 |
}
|
193 |
|
194 |
protected function post_rows( $current_post_id, $page = 1, $search = '' ) {
|
@@ -221,16 +210,7 @@ class P2P_Box {
|
|
221 |
);
|
222 |
|
223 |
foreach ( $candidate->posts as $post ) {
|
224 |
-
$
|
225 |
-
|
226 |
-
foreach ( $columns as $key => $field ) {
|
227 |
-
$row['columns'][] = array(
|
228 |
-
'column' => $key,
|
229 |
-
'content' => $field->render( $key, 0, $post->ID )
|
230 |
-
);
|
231 |
-
}
|
232 |
-
|
233 |
-
$data['rows'][] = $row;
|
234 |
}
|
235 |
|
236 |
if ( $candidate->total_pages > 1 ) {
|
@@ -250,7 +230,7 @@ class P2P_Box {
|
|
250 |
);
|
251 |
}
|
252 |
|
253 |
-
return
|
254 |
}
|
255 |
|
256 |
|
@@ -282,10 +262,10 @@ class P2P_Box {
|
|
282 |
if ( !$from || !$to )
|
283 |
die(-1);
|
284 |
|
285 |
-
$p2p_id = $this->ctype->
|
286 |
|
287 |
if ( $p2p_id )
|
288 |
-
echo $this->connection_row( $p2p_id, $to );
|
289 |
|
290 |
die;
|
291 |
}
|
@@ -297,13 +277,13 @@ class P2P_Box {
|
|
297 |
}
|
298 |
|
299 |
public function ajax_clear_connections() {
|
300 |
-
$this->ctype->
|
301 |
|
302 |
die(1);
|
303 |
}
|
304 |
|
305 |
public function ajax_search() {
|
306 |
-
$rows = $this->post_rows( $_GET['
|
307 |
|
308 |
if ( $rows ) {
|
309 |
$results = compact( 'rows' );
|
@@ -317,11 +297,21 @@ class P2P_Box {
|
|
317 |
}
|
318 |
|
319 |
protected function can_create_post() {
|
320 |
-
|
|
|
|
|
|
|
321 |
|
322 |
-
if ( count( $
|
323 |
return false;
|
324 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
return current_user_can( $this->ptype->cap->edit_posts );
|
326 |
}
|
327 |
|
@@ -335,27 +325,3 @@ class P2P_Box {
|
|
335 |
}
|
336 |
}
|
337 |
|
338 |
-
|
339 |
-
// Helpers
|
340 |
-
|
341 |
-
/**
|
342 |
-
* @internal
|
343 |
-
*/
|
344 |
-
function _p2p_mustache_render( $file, $data, $partials = array() ) {
|
345 |
-
$partial_data = array();
|
346 |
-
foreach ( $partials as $partial ) {
|
347 |
-
$partial_data[$partial] = _p2p_load_template( $partial . '.html' );
|
348 |
-
}
|
349 |
-
|
350 |
-
$m = new Mustache;
|
351 |
-
|
352 |
-
return $m->render( _p2p_load_template( $file ), $data, $partial_data );
|
353 |
-
}
|
354 |
-
|
355 |
-
/**
|
356 |
-
* @internal
|
357 |
-
*/
|
358 |
-
function _p2p_load_template( $file ) {
|
359 |
-
return file_get_contents( dirname(__FILE__) . '/templates/' . $file );
|
360 |
-
}
|
361 |
-
|
14 |
class P2P_Box {
|
15 |
private $ctype;
|
16 |
|
17 |
+
private $args;
|
18 |
|
19 |
+
private $ptype;
|
20 |
|
21 |
private $columns;
|
22 |
|
26 |
'post_status' => 'any',
|
27 |
);
|
28 |
|
29 |
+
function __construct( $args, $ctype ) {
|
30 |
+
$this->args = $args;
|
|
|
|
|
31 |
|
32 |
+
$this->ctype = $ctype;
|
|
|
33 |
|
34 |
+
$this->ptype = P2P_Util::get_first_valid_ptype( $this->ctype->get_other_post_type() );
|
|
|
35 |
|
36 |
add_filter( 'posts_search', array( __CLASS__, '_search_by_title' ), 10, 2 );
|
37 |
|
38 |
$this->init_columns();
|
39 |
}
|
40 |
|
41 |
+
public function init_scripts() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
wp_enqueue_style( 'p2p-admin', plugins_url( 'box.css', __FILE__ ), array(), P2P_PLUGIN_VERSION );
|
43 |
|
44 |
wp_enqueue_script( 'p2p-admin', plugins_url( 'box.js', __FILE__ ), array( 'jquery' ), P2P_PLUGIN_VERSION, true );
|
55 |
'title' => new P2P_Field_Title( $this->ptype->labels->singular_name ),
|
56 |
);
|
57 |
|
58 |
+
foreach ( $this->args->fields as $key => $data ) {
|
59 |
$this->columns[ $key ] = new P2P_Field_Generic( $data );
|
60 |
}
|
61 |
|
62 |
+
if ( method_exists( $this->ctype, 'get_orderby_key' ) ) {
|
63 |
+
$this->columns['order'] = new P2P_Field_Order( $this->ctype->get_orderby_key() );
|
64 |
}
|
65 |
}
|
66 |
|
71 |
$this->connected_posts = $this->ctype->get_connected( $post->ID, $qv )->posts;
|
72 |
|
73 |
$data = array(
|
74 |
+
'ctype-id' => $this->ctype->id,
|
75 |
+
'attributes' => $this->render_data_attributes(),
|
76 |
'connections' => $this->render_connections_table( $post ),
|
77 |
+
'create-connections' => $this->render_create_connections( $post ),
|
78 |
);
|
79 |
|
80 |
+
echo P2P_Mustache::render( 'box', $data );
|
81 |
+
}
|
82 |
+
|
83 |
+
protected function render_data_attributes() {
|
84 |
$data_attr = array(
|
85 |
'ctype_id' => $this->ctype->id,
|
86 |
'prevent_duplicates' => $this->ctype->prevent_duplicates,
|
87 |
+
'cardinality' => $this->ctype->accepts_single_connection() ? 'one' : 'many',
|
88 |
+
'direction' => $this->ctype->get_direction()
|
89 |
);
|
90 |
|
91 |
$data_attr_str = array();
|
92 |
foreach ( $data_attr as $key => $value )
|
93 |
$data_attr_str[] = "data-$key='" . $value . "'";
|
94 |
|
95 |
+
return implode( ' ', $data_attr_str );
|
|
|
|
|
96 |
}
|
97 |
|
98 |
protected function render_connections_table( $post ) {
|
101 |
if ( empty( $this->connected_posts ) )
|
102 |
$data['hide'] = 'style="display:none"';
|
103 |
|
104 |
+
$tbody = array();
|
105 |
foreach ( $this->connected_posts as $connected ) {
|
106 |
+
$tbody[] = $this->connection_row( $connected->p2p_id, $connected->ID );
|
107 |
}
|
108 |
$data['tbody'] = $tbody;
|
109 |
|
114 |
);
|
115 |
}
|
116 |
|
117 |
+
return $data;
|
118 |
}
|
119 |
|
120 |
protected function render_create_connections( $post ) {
|
121 |
$data = array(
|
122 |
+
'label' => __( 'Create connections:', P2P_TEXTDOMAIN )
|
123 |
);
|
124 |
|
125 |
+
if ( $this->ctype->accepts_single_connection() && !empty( $this->connected_posts ) )
|
126 |
$data['hide'] = 'style="display:none"';
|
127 |
|
128 |
// Search tab
|
129 |
+
$tab_content = P2P_Mustache::render( 'tab-search', array(
|
130 |
'placeholder' => $this->ptype->labels->search_items,
|
131 |
) );
|
132 |
|
146 |
|
147 |
// Create post tab
|
148 |
if ( $this->can_create_post() ) {
|
149 |
+
$tab_content = P2P_Mustache::render( 'tab-create-post', array(
|
150 |
'title' => $this->ptype->labels->add_new_item
|
151 |
) );
|
152 |
|
157 |
);
|
158 |
}
|
159 |
|
160 |
+
return $data;
|
161 |
+
}
|
162 |
+
|
163 |
+
protected function connection_row( $p2p_id, $post_id, $render = false ) {
|
164 |
+
return $this->table_row( $this->columns, $p2p_id, $post_id, $render );
|
165 |
}
|
166 |
|
167 |
+
protected function table_row( $columns, $p2p_id, $post_id, $render = false ) {
|
168 |
$data = array();
|
169 |
|
170 |
+
foreach ( $columns as $key => $field ) {
|
171 |
$data['columns'][] = array(
|
172 |
'column' => $key,
|
173 |
'content' => $field->render( $key, $p2p_id, $post_id )
|
174 |
);
|
175 |
}
|
176 |
|
177 |
+
if ( !$render )
|
178 |
+
return $data;
|
179 |
+
|
180 |
+
return P2P_Mustache::render( 'table-row', $data );
|
181 |
}
|
182 |
|
183 |
protected function post_rows( $current_post_id, $page = 1, $search = '' ) {
|
210 |
);
|
211 |
|
212 |
foreach ( $candidate->posts as $post ) {
|
213 |
+
$data['rows'][] = $this->table_row( $columns, 0, $post->ID );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
}
|
215 |
|
216 |
if ( $candidate->total_pages > 1 ) {
|
230 |
);
|
231 |
}
|
232 |
|
233 |
+
return P2P_Mustache::render( 'tab-list', $data );
|
234 |
}
|
235 |
|
236 |
|
262 |
if ( !$from || !$to )
|
263 |
die(-1);
|
264 |
|
265 |
+
$p2p_id = $this->ctype->connect( $from, $to );
|
266 |
|
267 |
if ( $p2p_id )
|
268 |
+
echo $this->connection_row( $p2p_id, $to, true );
|
269 |
|
270 |
die;
|
271 |
}
|
277 |
}
|
278 |
|
279 |
public function ajax_clear_connections() {
|
280 |
+
$this->ctype->disconnect_all( $_POST['from'] );
|
281 |
|
282 |
die(1);
|
283 |
}
|
284 |
|
285 |
public function ajax_search() {
|
286 |
+
$rows = $this->post_rows( $_GET['from'], $_GET['paged'], $_GET['s'] );
|
287 |
|
288 |
if ( $rows ) {
|
289 |
$results = compact( 'rows' );
|
297 |
}
|
298 |
|
299 |
protected function can_create_post() {
|
300 |
+
if ( !$this->args->can_create_post )
|
301 |
+
return false;
|
302 |
+
|
303 |
+
$base_qv = ( 'from' == $this->ctype->get_direction() ) ? $this->ctype->to_query_vars : $this->ctype->from_query_vars;
|
304 |
|
305 |
+
if ( count( $base_qv ) > 1 )
|
306 |
return false;
|
307 |
|
308 |
+
if ( count( $this->ctype->get_other_post_type() ) > 1 )
|
309 |
+
return false;
|
310 |
+
|
311 |
+
return $this->check_capability();
|
312 |
+
}
|
313 |
+
|
314 |
+
public function check_capability() {
|
315 |
return current_user_can( $this->ptype->cap->edit_posts );
|
316 |
}
|
317 |
|
325 |
}
|
326 |
}
|
327 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
admin/column-factory.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class P2P_Column_Factory {
|
4 |
+
|
5 |
+
private static $column_args = array();
|
6 |
+
|
7 |
+
static function register( $ctype_id, $column_args ) {
|
8 |
+
if ( isset( self::$column_args[$ctype_id] ) )
|
9 |
+
return false;
|
10 |
+
|
11 |
+
if ( !$column_args )
|
12 |
+
return false;
|
13 |
+
|
14 |
+
self::$column_args[$ctype_id] = $column_args;
|
15 |
+
|
16 |
+
return true;
|
17 |
+
}
|
18 |
+
|
19 |
+
function add_columns() {
|
20 |
+
$screen = get_current_screen();
|
21 |
+
|
22 |
+
if ( 'edit' != $screen->base )
|
23 |
+
return;
|
24 |
+
|
25 |
+
$post_type = $screen->post_type;
|
26 |
+
|
27 |
+
foreach ( self::$column_args as $ctype_id => $column_args ) {
|
28 |
+
$ctype = p2p_type( $ctype_id );
|
29 |
+
|
30 |
+
$directed = $ctype->find_direction( $post_type );
|
31 |
+
if ( !$directed )
|
32 |
+
continue;
|
33 |
+
|
34 |
+
if ( !( 'any' == $column_args || $directed->get_direction() == $column_args ) )
|
35 |
+
continue;
|
36 |
+
|
37 |
+
$column = new P2P_Column( $directed );
|
38 |
+
|
39 |
+
add_filter( "manage_{$screen->id}_columns", array( $column, 'add_column' ) );
|
40 |
+
add_action( "manage_{$post_type}_posts_custom_column", array( $column, 'display_column' ), 10, 2 );
|
41 |
+
}
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
add_action( 'admin_head', array( 'P2P_Column_Factory', 'add_columns' ) );
|
46 |
+
|
admin/column.php
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class P2P_Column {
|
4 |
+
|
5 |
+
protected $ctype;
|
6 |
+
|
7 |
+
protected $connected = array();
|
8 |
+
|
9 |
+
function __construct( $directed ) {
|
10 |
+
$this->ctype = $directed;
|
11 |
+
|
12 |
+
$this->ctype->lose_direction()->each_connected( $GLOBALS['wp_query'] );
|
13 |
+
|
14 |
+
$this->connected = scb_list_fold( $GLOBALS['wp_query']->posts, 'ID', 'connected' );
|
15 |
+
}
|
16 |
+
|
17 |
+
function add_column( $columns ) {
|
18 |
+
$columns['connected'] = $this->ctype->get_title();
|
19 |
+
|
20 |
+
return $columns;
|
21 |
+
}
|
22 |
+
|
23 |
+
function display_column( $column, $post_id ) {
|
24 |
+
if ( 'connected' != $column )
|
25 |
+
return;
|
26 |
+
|
27 |
+
foreach ( $this->connected[ $post_id ] as $post ) {
|
28 |
+
$args = array(
|
29 |
+
'post_type' => get_post_type( $post_id ),
|
30 |
+
'connected_type' => $this->ctype->id,
|
31 |
+
'connected' => $post->ID,
|
32 |
+
);
|
33 |
+
|
34 |
+
$url = add_query_arg( $args, admin_url( 'edit.php' ) );
|
35 |
+
|
36 |
+
echo html( 'li', html_link( $url, $post->post_title ) );
|
37 |
+
}
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
admin/fields.php
CHANGED
@@ -16,7 +16,7 @@ class P2P_Field_Create implements P2P_Field {
|
|
16 |
'title' => __( 'Create connection', P2P_TEXTDOMAIN )
|
17 |
);
|
18 |
|
19 |
-
return
|
20 |
}
|
21 |
}
|
22 |
|
@@ -30,7 +30,7 @@ class P2P_Field_Delete implements P2P_Field {
|
|
30 |
'title' => __( 'Delete all connections', P2P_TEXTDOMAIN )
|
31 |
);
|
32 |
|
33 |
-
return
|
34 |
}
|
35 |
|
36 |
function render( $key, $p2p_id, $post_id ) {
|
@@ -39,7 +39,7 @@ class P2P_Field_Delete implements P2P_Field {
|
|
39 |
'title' => __( 'Delete connection', P2P_TEXTDOMAIN )
|
40 |
);
|
41 |
|
42 |
-
return
|
43 |
}
|
44 |
}
|
45 |
|
@@ -84,7 +84,7 @@ class P2P_Field_Title implements P2P_Field {
|
|
84 |
|
85 |
function render( $key, $p2p_id, $post_id ) {
|
86 |
$data = array(
|
87 |
-
'title-attr' =>
|
88 |
'title' => get_post_field( 'post_title', $post_id ),
|
89 |
'url' => get_edit_post_link( $post_id ),
|
90 |
);
|
@@ -98,7 +98,7 @@ class P2P_Field_Title implements P2P_Field {
|
|
98 |
}
|
99 |
}
|
100 |
|
101 |
-
return
|
102 |
}
|
103 |
}
|
104 |
|
@@ -110,9 +110,6 @@ class P2P_Field_Generic implements P2P_Field {
|
|
110 |
protected $data;
|
111 |
|
112 |
function __construct( $data ) {
|
113 |
-
if ( !is_array( $data ) )
|
114 |
-
$data = array( 'title' => $data );
|
115 |
-
|
116 |
$this->data = $data;
|
117 |
}
|
118 |
|
@@ -121,20 +118,20 @@ class P2P_Field_Generic implements P2P_Field {
|
|
121 |
}
|
122 |
|
123 |
function render( $key, $p2p_id, $post_id ) {
|
124 |
-
$form = new scbForm(
|
125 |
-
array( $key => p2p_get_meta( $p2p_id, $key, true ) ),
|
126 |
-
array( 'p2p_meta', $p2p_id )
|
127 |
-
);
|
128 |
-
|
129 |
$args = array(
|
130 |
-
'
|
131 |
-
'
|
132 |
);
|
133 |
|
134 |
-
if ( isset( $this->data['values'] ) )
|
135 |
-
$args['type'] = 'select';
|
136 |
$args['value'] = $this->data['values'];
|
137 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
|
139 |
return $form->input( $args );
|
140 |
}
|
16 |
'title' => __( 'Create connection', P2P_TEXTDOMAIN )
|
17 |
);
|
18 |
|
19 |
+
return P2P_Mustache::render( 'column-create', $data );
|
20 |
}
|
21 |
}
|
22 |
|
30 |
'title' => __( 'Delete all connections', P2P_TEXTDOMAIN )
|
31 |
);
|
32 |
|
33 |
+
return P2P_Mustache::render( 'column-delete-all', $data );
|
34 |
}
|
35 |
|
36 |
function render( $key, $p2p_id, $post_id ) {
|
39 |
'title' => __( 'Delete connection', P2P_TEXTDOMAIN )
|
40 |
);
|
41 |
|
42 |
+
return P2P_Mustache::render( 'column-delete', $data );
|
43 |
}
|
44 |
}
|
45 |
|
84 |
|
85 |
function render( $key, $p2p_id, $post_id ) {
|
86 |
$data = array(
|
87 |
+
'title-attr' => get_permalink( $post_id ),
|
88 |
'title' => get_post_field( 'post_title', $post_id ),
|
89 |
'url' => get_edit_post_link( $post_id ),
|
90 |
);
|
98 |
}
|
99 |
}
|
100 |
|
101 |
+
return P2P_Mustache::render( 'column-title', $data );
|
102 |
}
|
103 |
}
|
104 |
|
110 |
protected $data;
|
111 |
|
112 |
function __construct( $data ) {
|
|
|
|
|
|
|
113 |
$this->data = $data;
|
114 |
}
|
115 |
|
118 |
}
|
119 |
|
120 |
function render( $key, $p2p_id, $post_id ) {
|
|
|
|
|
|
|
|
|
|
|
121 |
$args = array(
|
122 |
+
'name' => $key,
|
123 |
+
'type' => $this->data['type']
|
124 |
);
|
125 |
|
126 |
+
if ( isset( $this->data['values'] ) )
|
|
|
127 |
$args['value'] = $this->data['values'];
|
128 |
+
|
129 |
+
$single_value = ( 'checkbox' != $args['type'] );
|
130 |
+
|
131 |
+
$form = new scbForm(
|
132 |
+
array( $key => p2p_get_meta( $p2p_id, $key, $single_value ) ),
|
133 |
+
array( 'p2p_meta', $p2p_id )
|
134 |
+
);
|
135 |
|
136 |
return $form->input( $args );
|
137 |
}
|
admin/templates/box.html
CHANGED
@@ -1,4 +1,38 @@
|
|
|
|
|
|
1 |
<div class="p2p-box" {{attributes}}>
|
2 |
-
{{
|
3 |
-
{{{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
</div>
|
1 |
+
<input type="hidden" name="p2p_ctypes[]" value="{{ctype-id}}" />
|
2 |
+
|
3 |
<div class="p2p-box" {{attributes}}>
|
4 |
+
{{#connections}}
|
5 |
+
<table class="p2p-connections" {{{hide}}}>
|
6 |
+
<thead>
|
7 |
+
<tr>
|
8 |
+
{{#thead}}
|
9 |
+
<th class="p2p-col-{{column}}">{{{title}}}</th>
|
10 |
+
{{/thead}}
|
11 |
+
</tr>
|
12 |
+
</thead>
|
13 |
+
|
14 |
+
<tbody>
|
15 |
+
{{#tbody}}
|
16 |
+
{{>table-row}}
|
17 |
+
{{/tbody}}
|
18 |
+
</tbody>
|
19 |
+
</table>
|
20 |
+
{{/connections}}
|
21 |
+
|
22 |
+
{{#create-connections}}
|
23 |
+
<div class="p2p-create-connections" {{{hide}}}>
|
24 |
+
<p><strong>{{label}}</strong></p>
|
25 |
+
<ul class="wp-tab-bar clearfix">
|
26 |
+
{{#tabs}}
|
27 |
+
<li {{#is-active}}class="wp-tab-active"{{/is-active}} data-ref=".p2p-tab-{{tab-id}}"><a href="#">{{tab-title}}</a></li>
|
28 |
+
{{/tabs}}
|
29 |
+
</ul>
|
30 |
+
|
31 |
+
{{#tabs}}
|
32 |
+
<div class="p2p-tab-{{tab-id}} tabs-panel">
|
33 |
+
{{{tab-content}}}
|
34 |
+
</div>
|
35 |
+
{{/tabs}}
|
36 |
+
</div>
|
37 |
+
{{/create-connections}}
|
38 |
</div>
|
admin/templates/create-connections.html
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<div class="p2p-create-connections" {{{hide}}}>
|
2 |
-
<p><strong>{{create-label}}</strong></p>
|
3 |
-
|
4 |
-
<ul class="wp-tab-bar clearfix">
|
5 |
-
{{#tabs}}
|
6 |
-
<li {{#is-active}}class="wp-tab-active"{{/is-active}} data-ref=".p2p-tab-{{tab-id}}"><a href="#">{{tab-title}}</a></li>
|
7 |
-
{{/tabs}}
|
8 |
-
</ul>
|
9 |
-
|
10 |
-
{{#tabs}}
|
11 |
-
<div class="p2p-tab-{{tab-id}} tabs-panel">
|
12 |
-
{{{tab-content}}}
|
13 |
-
</div>
|
14 |
-
{{/tabs}}
|
15 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
admin/templates/table-row.html
CHANGED
@@ -1,7 +1,5 @@
|
|
1 |
<tr>
|
2 |
{{#columns}}
|
3 |
-
<td class="p2p-col-{{column}}">
|
4 |
-
{{{content}}}
|
5 |
-
</td>
|
6 |
{{/columns}}
|
7 |
</tr>
|
1 |
<tr>
|
2 |
{{#columns}}
|
3 |
+
<td class="p2p-col-{{column}}">{{{content}}}</td>
|
|
|
|
|
4 |
{{/columns}}
|
5 |
</tr>
|
admin/templates/table.html
DELETED
@@ -1,13 +0,0 @@
|
|
1 |
-
<table class="p2p-connections" {{{hide}}}>
|
2 |
-
<thead>
|
3 |
-
<tr>
|
4 |
-
{{#thead}}
|
5 |
-
<th class="p2p-col-{{column}}">{{{title}}}</th>
|
6 |
-
{{/thead}}
|
7 |
-
</tr>
|
8 |
-
</thead>
|
9 |
-
|
10 |
-
<tbody>
|
11 |
-
{{{tbody}}}
|
12 |
-
</tbody>
|
13 |
-
</table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
admin/utils.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @internal
|
5 |
+
*/
|
6 |
+
abstract class P2P_Mustache {
|
7 |
+
|
8 |
+
private static $loader;
|
9 |
+
private static $mustache;
|
10 |
+
|
11 |
+
public static function init() {
|
12 |
+
if ( !class_exists( 'Mustache' ) )
|
13 |
+
require dirname(__FILE__) . '/../mustache/Mustache.php';
|
14 |
+
|
15 |
+
if ( !class_exists( 'MustacheLoader' ) )
|
16 |
+
require dirname(__FILE__) . '/../mustache/MustacheLoader.php';
|
17 |
+
|
18 |
+
self::$loader = new MustacheLoader( dirname(__FILE__) . '/templates', 'html' );
|
19 |
+
|
20 |
+
self::$mustache = new Mustache( null, null, self::$loader );
|
21 |
+
}
|
22 |
+
|
23 |
+
public static function render( $template, $data ) {
|
24 |
+
return self::$mustache->render( self::$loader[$template], $data );
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
P2P_Mustache::init();
|
29 |
+
|
core/api.php
CHANGED
@@ -11,23 +11,29 @@
|
|
11 |
*
|
12 |
* - 'from' - string|array The first end of the connection.
|
13 |
*
|
|
|
|
|
14 |
* - 'to' - string|array The second end of the connection.
|
15 |
*
|
16 |
-
* - '
|
|
|
|
|
17 |
*
|
18 |
-
* - 'data' - array( key => value ) Metadata fields not editable by the user
|
19 |
*
|
20 |
-
* - '
|
21 |
*
|
22 |
* - 'prevent_duplicates' - bool Whether to disallow duplicate connections between the same two posts. Default: true.
|
23 |
*
|
24 |
-
* - '
|
|
|
|
|
25 |
*
|
26 |
-
* - 'reciprocal' - bool
|
27 |
*
|
28 |
-
* - '
|
29 |
*
|
30 |
-
* - '
|
31 |
*
|
32 |
* @param array $args
|
33 |
*
|
@@ -35,23 +41,72 @@
|
|
35 |
*/
|
36 |
function p2p_register_connection_type( $args ) {
|
37 |
if ( !did_action('init') ) {
|
38 |
-
trigger_error( "Connection types should not be registered before the 'init' hook."
|
39 |
}
|
40 |
|
41 |
$argv = func_get_args();
|
42 |
|
|
|
43 |
if ( count( $argv ) > 1 ) {
|
44 |
$args = array();
|
45 |
-
|
|
|
|
|
|
|
46 |
}
|
47 |
|
48 |
-
|
49 |
-
'
|
50 |
-
|
51 |
-
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
-
return
|
55 |
}
|
56 |
|
57 |
/**
|
@@ -62,7 +117,7 @@ function p2p_register_connection_type( $args ) {
|
|
62 |
* @return bool|object False if connection type not found, P2P_Connection_Type instance on success.
|
63 |
*/
|
64 |
function p2p_type( $id ) {
|
65 |
-
return P2P_Connection_Type::
|
66 |
}
|
67 |
|
68 |
/**
|
@@ -89,7 +144,8 @@ function p2p_split_posts( $posts, $key ) {
|
|
89 |
$buckets = array();
|
90 |
|
91 |
foreach ( $posts as $post ) {
|
92 |
-
$
|
|
|
93 |
}
|
94 |
|
95 |
return $buckets;
|
11 |
*
|
12 |
* - 'from' - string|array The first end of the connection.
|
13 |
*
|
14 |
+
* - 'from_query_vars' - array Additional query vars to pass to WP_Query. Default: none.
|
15 |
+
*
|
16 |
* - 'to' - string|array The second end of the connection.
|
17 |
*
|
18 |
+
* - 'to_query_vars' - array Additional query vars to pass to WP_Query. Default: none.
|
19 |
+
*
|
20 |
+
* - 'fields' - array( key => Title ) Metadata fields editable by the user. Default: none.
|
21 |
*
|
22 |
+
* - 'data' - array( key => value ) Metadata fields not editable by the user. Dfault: none.
|
23 |
*
|
24 |
+
* - 'cardinality' - string How many connection can each post have: 'one-to-many', 'many-to-one' or 'many-to-many'. Default: 'many-to-many'
|
25 |
*
|
26 |
* - 'prevent_duplicates' - bool Whether to disallow duplicate connections between the same two posts. Default: true.
|
27 |
*
|
28 |
+
* - 'sortable' - bool|string Whether to allow connections to be ordered via drag-and-drop. Can be 'from', 'to', 'any' or false. Default: false.
|
29 |
+
*
|
30 |
+
* - 'title' - string|array The box's title. Default: 'Connected {$post_type}s'
|
31 |
*
|
32 |
+
* - 'reciprocal' - bool For indeterminate connections: True means all connections are displayed in a single box. False means 'from' connections are shown in one box and 'to' connections are shown in another box. Default: false.
|
33 |
*
|
34 |
+
* - 'admin_box' - bool|string|array Whether and where to show the admin connections box.
|
35 |
*
|
36 |
+
* - 'can_create_post' - bool Whether to allow post creation via the connection box. Default: true.
|
37 |
*
|
38 |
* @param array $args
|
39 |
*
|
41 |
*/
|
42 |
function p2p_register_connection_type( $args ) {
|
43 |
if ( !did_action('init') ) {
|
44 |
+
trigger_error( "Connection types should not be registered before the 'init' hook." );
|
45 |
}
|
46 |
|
47 |
$argv = func_get_args();
|
48 |
|
49 |
+
// Back-compat begin
|
50 |
if ( count( $argv ) > 1 ) {
|
51 |
$args = array();
|
52 |
+
foreach ( array( 'from', 'to', 'reciprocal' ) as $i => $key ) {
|
53 |
+
if ( isset( $argv[ $i ] ) )
|
54 |
+
$args[ $key ] = $argv[ $i ];
|
55 |
+
}
|
56 |
}
|
57 |
|
58 |
+
if ( isset( $args['show_ui'] ) ) {
|
59 |
+
$args['admin_box'] = array(
|
60 |
+
'show' => _p2p_pluck( $args, 'show_ui' )
|
61 |
+
);
|
62 |
+
if ( isset( $args['context'] ) )
|
63 |
+
$args['admin_box']['context'] = _p2p_pluck( $args, 'context' );
|
64 |
+
}
|
65 |
+
// Back-compat end
|
66 |
+
|
67 |
+
// Box args
|
68 |
+
if ( isset( $args['admin_box'] ) ) {
|
69 |
+
$metabox_args = _p2p_pluck( $args, 'admin_box' );
|
70 |
+
if ( !is_array( $metabox_args ) )
|
71 |
+
$metabox_args = array( 'show' => $metabox_args );
|
72 |
+
} else {
|
73 |
+
$metabox_args = array();
|
74 |
+
}
|
75 |
+
|
76 |
+
foreach ( array( 'fields', 'can_create_post' ) as $key ) {
|
77 |
+
if ( isset( $args[ $key ] ) ) {
|
78 |
+
$metabox_args[ $key ] = _p2p_pluck( $args, $key );
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
// Column args
|
83 |
+
if ( isset( $args['admin_column'] ) ) {
|
84 |
+
$column_args = _p2p_pluck( $args, 'admin_column' );
|
85 |
+
} else {
|
86 |
+
$column_args = false;
|
87 |
+
}
|
88 |
+
|
89 |
+
$ctype = P2P_Connection_Type::register( $args );
|
90 |
+
|
91 |
+
if ( is_admin() ) {
|
92 |
+
P2P_Box_Factory::register( $ctype->id, $metabox_args );
|
93 |
+
P2P_Column_Factory::register( $ctype->id, $column_args );
|
94 |
+
}
|
95 |
+
|
96 |
+
return $ctype;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* @internal
|
101 |
+
*/
|
102 |
+
function _p2p_get_field_type( $args ) {
|
103 |
+
if ( isset( $args['type'] ) )
|
104 |
+
return $args['type'];
|
105 |
+
|
106 |
+
if ( isset( $args['values'] ) && is_array( $args['values'] ) )
|
107 |
+
return 'select';
|
108 |
|
109 |
+
return 'text';
|
110 |
}
|
111 |
|
112 |
/**
|
117 |
* @return bool|object False if connection type not found, P2P_Connection_Type instance on success.
|
118 |
*/
|
119 |
function p2p_type( $id ) {
|
120 |
+
return P2P_Connection_Type::get_instance( $id );
|
121 |
}
|
122 |
|
123 |
/**
|
144 |
$buckets = array();
|
145 |
|
146 |
foreach ( $posts as $post ) {
|
147 |
+
$value = p2p_get_meta( $post->p2p_id, $key, true );
|
148 |
+
$buckets[ $value ][] = $post;
|
149 |
}
|
150 |
|
151 |
return $buckets;
|
core/directed-type.php
CHANGED
@@ -26,88 +26,108 @@ class P2P_Directed_Connection_Type {
|
|
26 |
}
|
27 |
|
28 |
function __get( $key ) {
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
|
|
31 |
|
32 |
-
|
33 |
-
|
|
|
34 |
|
35 |
-
|
|
|
36 |
}
|
37 |
|
38 |
public function lose_direction() {
|
39 |
return $this->ctype;
|
40 |
}
|
41 |
|
42 |
-
public function
|
43 |
-
|
44 |
-
|
45 |
-
if ( is_array( $title ) ) {
|
46 |
-
$key = ( 'to' == $this->direction ) ? 'to' : 'from';
|
47 |
|
48 |
-
|
49 |
-
|
50 |
-
else
|
51 |
-
$title = '';
|
52 |
-
}
|
53 |
|
54 |
-
return $title;
|
55 |
}
|
56 |
|
57 |
-
public function
|
58 |
-
return '
|
59 |
}
|
60 |
|
61 |
-
public function
|
62 |
-
return $this->
|
63 |
}
|
64 |
|
65 |
-
private function
|
66 |
$base_qv = ( 'from' == $this->direction ) ? $this->to_query_vars : $this->from_query_vars;
|
67 |
|
68 |
-
return array_merge( $
|
69 |
'suppress_filters' => false,
|
70 |
-
'ignore_sticky_posts' => true
|
71 |
) );
|
72 |
}
|
73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
public function get_connected( $post_id, $extra_qv = array() ) {
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
$args['connected_query'] = array(
|
78 |
'posts' => $post_id,
|
79 |
'direction' => $this->direction
|
80 |
);
|
81 |
|
82 |
-
|
83 |
-
|
84 |
-
if ( $this->is_sortable() ) {
|
85 |
-
_p2p_append( $args, array(
|
86 |
-
'connected_orderby' => $this->sortable,
|
87 |
-
'connected_order' => 'ASC',
|
88 |
-
'connected_order_num' => true,
|
89 |
-
) );
|
90 |
-
}
|
91 |
-
|
92 |
-
$args = apply_filters( 'p2p_connected_args', $args, $this );
|
93 |
-
|
94 |
-
return new WP_Query( $args );
|
95 |
}
|
96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
public function get_connectable( $post_id, $extra_qv = array() ) {
|
98 |
-
$args = $this->
|
99 |
|
100 |
if ( 'one' == $this->other_cardinality ) {
|
101 |
-
$
|
102 |
-
}
|
103 |
-
$
|
104 |
}
|
105 |
|
106 |
-
if (
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
}
|
109 |
|
110 |
-
$args = apply_filters( 'p2p_connectable_args', $args, $this );
|
111 |
|
112 |
return new WP_Query( $args );
|
113 |
}
|
@@ -116,11 +136,19 @@ class P2P_Directed_Connection_Type {
|
|
116 |
$connected = $this->get_connected( $from, array( 'post__in' => array( $to ) ) );
|
117 |
|
118 |
if ( !empty( $connected->posts ) )
|
119 |
-
return $connected->posts[0]->p2p_id;
|
120 |
|
121 |
return false;
|
122 |
}
|
123 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
public function connect( $from, $to ) {
|
125 |
if ( !get_post( $from ) || !get_post( $to ) )
|
126 |
return false;
|
@@ -149,15 +177,26 @@ class P2P_Directed_Connection_Type {
|
|
149 |
return $p2p_id;
|
150 |
}
|
151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
public function disconnect( $from, $to ) {
|
153 |
return P2P_Storage::delete( $this->get_p2p_id( $from, $to ) );
|
154 |
}
|
155 |
|
|
|
|
|
|
|
|
|
|
|
156 |
public function disconnect_all( $from ) {
|
157 |
$connected = $this->get_connected( $from );
|
158 |
|
159 |
-
foreach (
|
160 |
-
P2P_Storage::delete( $p2p_id );
|
161 |
}
|
162 |
}
|
163 |
|
26 |
}
|
27 |
|
28 |
function __get( $key ) {
|
29 |
+
return $this->ctype->$key;
|
30 |
+
}
|
31 |
+
|
32 |
+
function __isset( $key ) {
|
33 |
+
return isset( $this->ctype->$key );
|
34 |
+
}
|
35 |
|
36 |
+
public function get_direction() {
|
37 |
+
return $this->direction;
|
38 |
+
}
|
39 |
|
40 |
+
public function set_direction( $direction ) {
|
41 |
+
return $this->ctype->set_direction( $direction );
|
42 |
}
|
43 |
|
44 |
public function lose_direction() {
|
45 |
return $this->ctype;
|
46 |
}
|
47 |
|
48 |
+
public function accepts_single_connection() {
|
49 |
+
return 'one' == $this->cardinality;
|
50 |
+
}
|
|
|
|
|
51 |
|
52 |
+
public function get_title() {
|
53 |
+
$key = ( 'to' == $this->direction ) ? 'to' : 'from';
|
|
|
|
|
|
|
54 |
|
55 |
+
return $this->title[ $key ];
|
56 |
}
|
57 |
|
58 |
+
public function get_current_post_type() {
|
59 |
+
return 'to' == $this->direction ? $this->to : $this->from;
|
60 |
}
|
61 |
|
62 |
+
public function get_other_post_type() {
|
63 |
+
return 'to' == $this->direction ? $this->from : $this->to;
|
64 |
}
|
65 |
|
66 |
+
private function get_base_qv() {
|
67 |
$base_qv = ( 'from' == $this->direction ) ? $this->to_query_vars : $this->from_query_vars;
|
68 |
|
69 |
+
return array_merge( $base_qv, array(
|
70 |
'suppress_filters' => false,
|
71 |
+
'ignore_sticky_posts' => true,
|
72 |
) );
|
73 |
}
|
74 |
|
75 |
+
/**
|
76 |
+
* Get a list of posts that are connected to a given post.
|
77 |
+
*
|
78 |
+
* @param int|array $post_id A post id or an array of post ids.
|
79 |
+
* @param array $extra_qv Additional query variables to use.
|
80 |
+
*
|
81 |
+
* @return A WP_Query instance on success.
|
82 |
+
*/
|
83 |
public function get_connected( $post_id, $extra_qv = array() ) {
|
84 |
+
return new WP_Query( $this->get_connected_args( $post_id, $extra_qv ) );
|
85 |
+
}
|
86 |
+
|
87 |
+
public function get_connected_args( $post_id, $extra_qv = array() ) {
|
88 |
+
$args = array_merge( $extra_qv, $this->get_base_qv() );
|
89 |
+
|
90 |
+
// don't completely overwrite 'connected_meta', but ensure that $this->data is added
|
91 |
+
$args = array_merge_recursive( $args, array(
|
92 |
+
'connected_meta' => $this->data
|
93 |
+
) );
|
94 |
|
95 |
$args['connected_query'] = array(
|
96 |
'posts' => $post_id,
|
97 |
'direction' => $this->direction
|
98 |
);
|
99 |
|
100 |
+
return apply_filters( 'p2p_connected_args', $args, $this, $post_id );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
}
|
102 |
|
103 |
+
/**
|
104 |
+
* Get a list of posts that could be connected to a given post.
|
105 |
+
*
|
106 |
+
* @param int $post_id A post id.
|
107 |
+
* @param array $extra_qv Additional query variables to use.
|
108 |
+
*
|
109 |
+
* @return bool|object False on failure; A WP_Query instance on success.
|
110 |
+
*/
|
111 |
public function get_connectable( $post_id, $extra_qv = array() ) {
|
112 |
+
$args = array_merge( $this->get_base_qv(), $extra_qv );
|
113 |
|
114 |
if ( 'one' == $this->other_cardinality ) {
|
115 |
+
$to_check = 'any';
|
116 |
+
} elseif ( $this->prevent_duplicates ) {
|
117 |
+
$to_check = $post_id;
|
118 |
}
|
119 |
|
120 |
+
if ( isset( $to_check ) ) {
|
121 |
+
$connected = $this->get_connected( $to_check, array( 'fields' => 'ids' ) )->posts;
|
122 |
+
|
123 |
+
if ( !empty( $connected ) ) {
|
124 |
+
$args = array_merge_recursive( $args, array(
|
125 |
+
'post__not_in' => $connected
|
126 |
+
) );
|
127 |
+
}
|
128 |
}
|
129 |
|
130 |
+
$args = apply_filters( 'p2p_connectable_args', $args, $this, $post_id );
|
131 |
|
132 |
return new WP_Query( $args );
|
133 |
}
|
136 |
$connected = $this->get_connected( $from, array( 'post__in' => array( $to ) ) );
|
137 |
|
138 |
if ( !empty( $connected->posts ) )
|
139 |
+
return (int) $connected->posts[0]->p2p_id;
|
140 |
|
141 |
return false;
|
142 |
}
|
143 |
|
144 |
+
/**
|
145 |
+
* Connect two posts.
|
146 |
+
*
|
147 |
+
* @param int The first end of the connection.
|
148 |
+
* @param int The second end of the connection.
|
149 |
+
*
|
150 |
+
* @return int p2p_id
|
151 |
+
*/
|
152 |
public function connect( $from, $to ) {
|
153 |
if ( !get_post( $from ) || !get_post( $to ) )
|
154 |
return false;
|
177 |
return $p2p_id;
|
178 |
}
|
179 |
|
180 |
+
/**
|
181 |
+
* Disconnect two posts.
|
182 |
+
*
|
183 |
+
* @param int The first end of the connection.
|
184 |
+
* @param int The second end of the connection.
|
185 |
+
*/
|
186 |
public function disconnect( $from, $to ) {
|
187 |
return P2P_Storage::delete( $this->get_p2p_id( $from, $to ) );
|
188 |
}
|
189 |
|
190 |
+
/**
|
191 |
+
* Delete all connections for a certain post.
|
192 |
+
*
|
193 |
+
* @param int The post id.
|
194 |
+
*/
|
195 |
public function disconnect_all( $from ) {
|
196 |
$connected = $this->get_connected( $from );
|
197 |
|
198 |
+
foreach ( $connected->posts as $post )
|
199 |
+
P2P_Storage::delete( $post->p2p_id );
|
200 |
}
|
201 |
}
|
202 |
|
core/ordered-type.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class P2P_Ordered_Connection_Type extends P2P_Directed_Connection_Type {
|
4 |
+
|
5 |
+
protected $orderby_key;
|
6 |
+
|
7 |
+
function __construct( $ctype, $direction, $orderby_key ) {
|
8 |
+
$this->orderby_key = $orderby_key;
|
9 |
+
|
10 |
+
parent::__construct( $ctype, $direction );
|
11 |
+
}
|
12 |
+
|
13 |
+
public function get_orderby_key() {
|
14 |
+
return $this->orderby_key;
|
15 |
+
}
|
16 |
+
|
17 |
+
public function get_connected( $post_id, $extra_qv = array() ) {
|
18 |
+
$extra_qv = wp_parse_args( $extra_qv, array(
|
19 |
+
'connected_orderby' => $this->get_orderby_key(),
|
20 |
+
'connected_order' => 'ASC',
|
21 |
+
'connected_order_num' => true,
|
22 |
+
) );
|
23 |
+
|
24 |
+
return parent::get_connected( $post_id, $extra_qv );
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
core/query.php
CHANGED
@@ -6,9 +6,9 @@
|
|
6 |
class P2P_Query {
|
7 |
|
8 |
function init() {
|
9 |
-
add_action( 'parse_query', array(
|
10 |
-
add_filter( 'posts_clauses', array(
|
11 |
-
add_filter( 'the_posts', array(
|
12 |
}
|
13 |
|
14 |
function parse_legacy_qv( $wp_query ) {
|
@@ -118,7 +118,7 @@ class P2P_Query {
|
|
118 |
/**
|
119 |
* Pre-populates the p2p meta cache to decrease the number of queries.
|
120 |
*/
|
121 |
-
function
|
122 |
if ( empty( $the_posts ) )
|
123 |
return $the_posts;
|
124 |
|
6 |
class P2P_Query {
|
7 |
|
8 |
function init() {
|
9 |
+
add_action( 'parse_query', array( __CLASS__, 'parse_legacy_qv' ) );
|
10 |
+
add_filter( 'posts_clauses', array( __CLASS__, 'posts_clauses' ), 10, 2 );
|
11 |
+
add_filter( 'the_posts', array( __CLASS__, 'cache_p2p_meta' ), 11, 2 );
|
12 |
}
|
13 |
|
14 |
function parse_legacy_qv( $wp_query ) {
|
118 |
/**
|
119 |
* Pre-populates the p2p meta cache to decrease the number of queries.
|
120 |
*/
|
121 |
+
function cache_p2p_meta( $the_posts, $wp_query ) {
|
122 |
if ( empty( $the_posts ) )
|
123 |
return $the_posts;
|
124 |
|
core/storage.php
CHANGED
@@ -2,6 +2,9 @@
|
|
2 |
|
3 |
class P2P_Storage {
|
4 |
|
|
|
|
|
|
|
5 |
private static $version = 3;
|
6 |
|
7 |
function init() {
|
2 |
|
3 |
class P2P_Storage {
|
4 |
|
5 |
+
// Use P2P_Connection_Type
|
6 |
+
private function __construct() {}
|
7 |
+
|
8 |
private static $version = 3;
|
9 |
|
10 |
function init() {
|
core/type.php
CHANGED
@@ -12,7 +12,7 @@ class P2P_Connection_Type {
|
|
12 |
'from_query_vars' => array(),
|
13 |
'to_query_vars' => array(),
|
14 |
'data' => array(),
|
15 |
-
'reciprocal' =>
|
16 |
'cardinality' => 'many-to-many',
|
17 |
'prevent_duplicates' => true,
|
18 |
'sortable' => false,
|
@@ -42,10 +42,11 @@ class P2P_Connection_Type {
|
|
42 |
return self::$instances[ $id ] = new P2P_Connection_Type( $args );
|
43 |
}
|
44 |
|
45 |
-
public function
|
46 |
-
|
47 |
-
|
48 |
|
|
|
49 |
if ( isset( self::$instances[ $hash ] ) )
|
50 |
return self::$instances[ $hash ];
|
51 |
|
@@ -54,55 +55,82 @@ class P2P_Connection_Type {
|
|
54 |
|
55 |
|
56 |
protected $args;
|
|
|
57 |
|
58 |
protected function __construct( $args ) {
|
59 |
$this->args = $args;
|
60 |
|
61 |
$common = array_intersect( $this->from, $this->to );
|
62 |
|
63 |
-
if ( !empty( $common )
|
64 |
-
$this->
|
65 |
|
66 |
-
|
67 |
-
$this->args['reciprocal'] = ( $this->from == $this->to );
|
68 |
}
|
69 |
|
70 |
public function __get( $key ) {
|
71 |
-
if (
|
72 |
return $this->args[ "{$key}_query_vars" ]['post_type'];
|
73 |
|
|
|
|
|
|
|
74 |
return $this->args[$key];
|
75 |
}
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
/**
|
78 |
-
*
|
79 |
*
|
80 |
* @param int|string $arg A post id or a post type.
|
|
|
81 |
*
|
82 |
-
* @return bool|string False on failure,
|
83 |
*/
|
84 |
-
public function find_direction( $arg ) {
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
return false;
|
89 |
-
$post_type = $post->post_type;
|
90 |
-
} else {
|
91 |
-
$post_type = $arg;
|
92 |
-
}
|
93 |
|
94 |
-
|
95 |
-
|
96 |
-
$direction = 'any';
|
97 |
-
else
|
98 |
-
$direction = 'from';
|
99 |
-
} elseif ( in_array( $post_type, $this->to ) ) {
|
100 |
-
$direction = 'to';
|
101 |
-
} else {
|
102 |
return false;
|
103 |
-
}
|
104 |
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
}
|
107 |
|
108 |
/**
|
@@ -164,78 +192,90 @@ class P2P_Connection_Type {
|
|
164 |
}
|
165 |
|
166 |
/**
|
167 |
-
* Get a list of posts
|
168 |
*
|
169 |
-
* @param int $post_id A post id
|
170 |
* @param array $extra_qv Additional query variables to use.
|
171 |
*
|
172 |
* @return bool|object False on failure; A WP_Query instance on success.
|
173 |
*/
|
174 |
-
public function
|
175 |
-
$
|
176 |
-
|
|
|
|
|
177 |
return false;
|
178 |
|
179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
}
|
181 |
|
182 |
/**
|
183 |
-
* Get
|
184 |
*
|
185 |
-
* @param int
|
186 |
-
* @param
|
187 |
*
|
188 |
-
* @return bool|object False on failure
|
189 |
*/
|
190 |
-
public function
|
191 |
-
|
192 |
-
if ( !$directed )
|
193 |
-
return false;
|
194 |
-
|
195 |
-
return $directed->get_connectable( $post_id, $extra_qv );
|
196 |
}
|
197 |
|
198 |
/**
|
199 |
-
*
|
200 |
*
|
201 |
* @param int The first end of the connection.
|
202 |
* @param int The second end of the connection.
|
203 |
*
|
204 |
-
* @return
|
205 |
*/
|
206 |
-
public function
|
207 |
-
|
208 |
-
if ( !$directed )
|
209 |
-
return false;
|
210 |
-
|
211 |
-
return $directed->connect( $from, $to );
|
212 |
}
|
213 |
|
214 |
/**
|
215 |
-
*
|
216 |
*
|
217 |
* @param int The first end of the connection.
|
218 |
* @param int The second end of the connection.
|
|
|
|
|
|
|
219 |
*/
|
220 |
-
public function
|
221 |
-
$directed = $this->find_direction( $
|
222 |
if ( !$directed )
|
223 |
return false;
|
224 |
|
225 |
-
|
226 |
-
|
227 |
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
$
|
235 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
return false;
|
237 |
|
238 |
-
return $
|
239 |
}
|
240 |
|
241 |
/**
|
@@ -246,13 +286,5 @@ class P2P_Connection_Type {
|
|
246 |
public function delete_connection( $p2p_id ) {
|
247 |
return P2P_Storage::delete( $p2p_id );
|
248 |
}
|
249 |
-
|
250 |
-
public function get_p2p_id( $from, $to ) {
|
251 |
-
$directed = $this->find_direction( $from );
|
252 |
-
if ( !$directed )
|
253 |
-
return false;
|
254 |
-
|
255 |
-
return $directed->get_p2p_id( $from, $to );
|
256 |
-
}
|
257 |
}
|
258 |
|
12 |
'from_query_vars' => array(),
|
13 |
'to_query_vars' => array(),
|
14 |
'data' => array(),
|
15 |
+
'reciprocal' => false,
|
16 |
'cardinality' => 'many-to-many',
|
17 |
'prevent_duplicates' => true,
|
18 |
'sortable' => false,
|
42 |
return self::$instances[ $id ] = new P2P_Connection_Type( $args );
|
43 |
}
|
44 |
|
45 |
+
public function get_all_instances() {
|
46 |
+
return self::$instances;
|
47 |
+
}
|
48 |
|
49 |
+
public function get_instance( $hash ) {
|
50 |
if ( isset( self::$instances[ $hash ] ) )
|
51 |
return self::$instances[ $hash ];
|
52 |
|
55 |
|
56 |
|
57 |
protected $args;
|
58 |
+
protected $indeterminate;
|
59 |
|
60 |
protected function __construct( $args ) {
|
61 |
$this->args = $args;
|
62 |
|
63 |
$common = array_intersect( $this->from, $this->to );
|
64 |
|
65 |
+
if ( !empty( $common ) )
|
66 |
+
$this->indeterminate = true;
|
67 |
|
68 |
+
$this->args['title'] = P2P_Util::expand_title( $this->args['title'], $this->from, $this->to );
|
|
|
69 |
}
|
70 |
|
71 |
public function __get( $key ) {
|
72 |
+
if ( 'from' == $key || 'to' == $key )
|
73 |
return $this->args[ "{$key}_query_vars" ]['post_type'];
|
74 |
|
75 |
+
if ( 'indeterminate' == $key )
|
76 |
+
return $this->indeterminate;
|
77 |
+
|
78 |
return $this->args[$key];
|
79 |
}
|
80 |
|
81 |
+
public function __isset( $key ) {
|
82 |
+
return isset( $this->args[$key] );
|
83 |
+
}
|
84 |
+
|
85 |
+
public function __call( $method, $args ) {
|
86 |
+
$directed = $this->find_direction( $args[0] );
|
87 |
+
if ( !$directed )
|
88 |
+
return false;
|
89 |
+
|
90 |
+
return call_user_func_array( array( $directed, $method ), $args );
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Set the direction.
|
95 |
+
*
|
96 |
+
* @param string $direction Can be 'from', 'to' or 'any'.
|
97 |
+
*
|
98 |
+
* @return object P2P_Directed_Connection_Type instance
|
99 |
+
*/
|
100 |
+
public function set_direction( $direction ) {
|
101 |
+
if ( !in_array( $direction, array( 'from', 'to', 'any' ) ) )
|
102 |
+
return false;
|
103 |
+
|
104 |
+
if ( $orderby_key = P2P_Util::get_orderby_key( $this->sortable, $direction ) )
|
105 |
+
return new P2P_Ordered_Connection_Type( $this, $direction, $orderby_key );
|
106 |
+
|
107 |
+
return new P2P_Directed_Connection_Type( $this, $direction );
|
108 |
+
}
|
109 |
+
|
110 |
/**
|
111 |
+
* Attempt to guess direction based on a post id or post type.
|
112 |
*
|
113 |
* @param int|string $arg A post id or a post type.
|
114 |
+
* @param bool Whether to return an instance of P2P_Directed_Connection_Type or just the direction
|
115 |
*
|
116 |
+
* @return bool|object|string False on failure, P2P_Directed_Connection_Type instance or direction on success.
|
117 |
*/
|
118 |
+
public function find_direction( $arg, $instantiate = true ) {
|
119 |
+
$post_type = P2P_Util::find_post_type( $arg );
|
120 |
+
if ( !$post_type )
|
121 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
122 |
|
123 |
+
$direction = P2P_Util::get_direction( $post_type, $this->from, $this->to );
|
124 |
+
if ( !$direction )
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
return false;
|
|
|
126 |
|
127 |
+
if ( $this->indeterminate )
|
128 |
+
$direction = $this->reciprocal ? 'any' : 'from';
|
129 |
+
|
130 |
+
if ( $instantiate )
|
131 |
+
return $this->set_direction( $direction );
|
132 |
+
|
133 |
+
return $direction;
|
134 |
}
|
135 |
|
136 |
/**
|
192 |
}
|
193 |
|
194 |
/**
|
195 |
+
* Get a list of posts connected to other posts connected to a post.
|
196 |
*
|
197 |
+
* @param int|array $post_id A post id or array of post ids
|
198 |
* @param array $extra_qv Additional query variables to use.
|
199 |
*
|
200 |
* @return bool|object False on failure; A WP_Query instance on success.
|
201 |
*/
|
202 |
+
public function get_related( $post_id, $extra_qv = array() ) {
|
203 |
+
$post_id = (array) $post_id;
|
204 |
+
|
205 |
+
$connected = $this->get_connected( $post_id, $extra_qv );
|
206 |
+
if ( !$connected )
|
207 |
return false;
|
208 |
|
209 |
+
if ( !$connected->have_posts() )
|
210 |
+
return $connected;
|
211 |
+
|
212 |
+
$connected_ids = wp_list_pluck( $connected->posts, 'ID' );
|
213 |
+
|
214 |
+
return $this->get_connected( $connected_ids, array(
|
215 |
+
'post__not_in' => $post_id,
|
216 |
+
) );
|
217 |
}
|
218 |
|
219 |
/**
|
220 |
+
* Get the previous post in an ordered connection.
|
221 |
*
|
222 |
+
* @param int The first end of the connection.
|
223 |
+
* @param int The second end of the connection.
|
224 |
*
|
225 |
+
* @return bool|object False on failure, post object on success
|
226 |
*/
|
227 |
+
public function get_previous( $from, $to ) {
|
228 |
+
return $this->get_adjacent( $from, $to, -1 );
|
|
|
|
|
|
|
|
|
229 |
}
|
230 |
|
231 |
/**
|
232 |
+
* Get the next post in an ordered connection.
|
233 |
*
|
234 |
* @param int The first end of the connection.
|
235 |
* @param int The second end of the connection.
|
236 |
*
|
237 |
+
* @return bool|object False on failure, post object on success
|
238 |
*/
|
239 |
+
public function get_next( $from, $to ) {
|
240 |
+
return $this->get_adjacent( $from, $to, +1 );
|
|
|
|
|
|
|
|
|
241 |
}
|
242 |
|
243 |
/**
|
244 |
+
* Get another post in an ordered connection.
|
245 |
*
|
246 |
* @param int The first end of the connection.
|
247 |
* @param int The second end of the connection.
|
248 |
+
* @param int The position relative to the first parameter
|
249 |
+
*
|
250 |
+
* @return bool|object False on failure, post object on success
|
251 |
*/
|
252 |
+
public function get_adjacent( $from, $to, $which ) {
|
253 |
+
$directed = $this->find_direction( $to );
|
254 |
if ( !$directed )
|
255 |
return false;
|
256 |
|
257 |
+
if ( !method_exists( $directed, 'get_orderby_key' ) )
|
258 |
+
return false;
|
259 |
|
260 |
+
$p2p_id = $directed->get_p2p_id( $to, $from );
|
261 |
+
if ( !$p2p_id )
|
262 |
+
return false;
|
263 |
+
|
264 |
+
$order = (int) p2p_get_meta( $p2p_id, $directed->get_orderby_key(), true );
|
265 |
+
|
266 |
+
$adjacent = $directed->get_connected( $to, array(
|
267 |
+
'connected_meta' => array(
|
268 |
+
array(
|
269 |
+
'key' => $directed->get_orderby_key(),
|
270 |
+
'value' => $order + $which
|
271 |
+
)
|
272 |
+
)
|
273 |
+
) )->posts;
|
274 |
+
|
275 |
+
if ( empty( $adjacent ) )
|
276 |
return false;
|
277 |
|
278 |
+
return $adjacent[0];
|
279 |
}
|
280 |
|
281 |
/**
|
286 |
public function delete_connection( $p2p_id ) {
|
287 |
return P2P_Storage::delete( $p2p_id );
|
288 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
}
|
290 |
|
core/url-query.php
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class P2P_URL_Query {
|
4 |
+
|
5 |
+
function init() {
|
6 |
+
add_filter( 'query_vars', array( __CLASS__, 'query_vars' ) );
|
7 |
+
add_filter( 'request', array( __CLASS__, 'request' ) );
|
8 |
+
}
|
9 |
+
|
10 |
+
function query_vars( $public_qv ) {
|
11 |
+
$public_qv[] = 'connected_type';
|
12 |
+
$public_qv[] = 'connected';
|
13 |
+
|
14 |
+
return $public_qv;
|
15 |
+
}
|
16 |
+
|
17 |
+
function request( $request ) {
|
18 |
+
if ( !isset( $request['connected_type'] ) || !isset( $request['connected'] ) )
|
19 |
+
return $request;
|
20 |
+
|
21 |
+
$connected_arg = _p2p_pluck( $request, 'connected' );
|
22 |
+
|
23 |
+
$ctype = p2p_type( _p2p_pluck( $request, 'connected_type' ) );
|
24 |
+
if ( !$ctype )
|
25 |
+
return array( 'year' => 2525 );
|
26 |
+
|
27 |
+
$directed = $ctype->find_direction( $connected_arg );
|
28 |
+
if ( !$directed )
|
29 |
+
return array( 'year' => 2525 );
|
30 |
+
|
31 |
+
return $directed->get_connected_args( $connected_arg, $request );
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
P2P_URL_Query::init();
|
36 |
+
|
core/util.php
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Various utilities for working with connection types.
|
5 |
+
*
|
6 |
+
* They come wit no backwards-compatibility warantee.
|
7 |
+
*/
|
8 |
+
abstract class P2P_Util {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Attempt to find a post type.
|
12 |
+
*
|
13 |
+
* @param mixed A post type, a post id, a post object, an array of post ids or of objects.
|
14 |
+
*
|
15 |
+
* @return bool|string False on failure, post type on success.
|
16 |
+
*/
|
17 |
+
static function find_post_type( $arg ) {
|
18 |
+
if ( is_array( $arg ) ) {
|
19 |
+
$arg = reset( $arg );
|
20 |
+
}
|
21 |
+
|
22 |
+
if ( is_object( $arg ) ) {
|
23 |
+
$post_type = $arg->post_type;
|
24 |
+
} elseif ( $post_id = (int) $arg ) {
|
25 |
+
$post = get_post( $post_id );
|
26 |
+
if ( !$post )
|
27 |
+
return false;
|
28 |
+
$post_type = $post->post_type;
|
29 |
+
} else {
|
30 |
+
$post_type = $arg;
|
31 |
+
}
|
32 |
+
|
33 |
+
if ( !post_type_exists( $post_type ) )
|
34 |
+
return false;
|
35 |
+
|
36 |
+
return $post_type;
|
37 |
+
}
|
38 |
+
|
39 |
+
static function get_first_valid_ptype( $post_types ) {
|
40 |
+
do {
|
41 |
+
$ptype = get_post_type_object( array_shift( $post_types ) );
|
42 |
+
} while ( !$ptype && !empty( $post_types ) );
|
43 |
+
|
44 |
+
return $ptype;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Check if a certain post or post type could have connections of this type.
|
49 |
+
*
|
50 |
+
* @param string A post type to check against.
|
51 |
+
* @param array List of post types (from).
|
52 |
+
* @param array List of post types (to).
|
53 |
+
*
|
54 |
+
* @return bool|string False on failure, direction on success.
|
55 |
+
*/
|
56 |
+
static function get_direction( $post_type, $from, $to ) {
|
57 |
+
if ( in_array( $post_type, $from ) ) {
|
58 |
+
$direction = 'from';
|
59 |
+
} elseif ( in_array( $post_type, $to ) ) {
|
60 |
+
$direction = 'to';
|
61 |
+
} else {
|
62 |
+
$direction = false;
|
63 |
+
}
|
64 |
+
|
65 |
+
return $direction;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @param string The direction in which ordering is allowed
|
70 |
+
* @param string The current direction
|
71 |
+
*
|
72 |
+
* @return bool|string False on failure, the connection field key otherwise
|
73 |
+
*/
|
74 |
+
static function get_orderby_key( $ordering_direction, $connection_direction ) {
|
75 |
+
if ( !$ordering_direction || 'any' == $connection_direction )
|
76 |
+
return false;
|
77 |
+
|
78 |
+
if ( 'any' == $ordering_direction || $connection_direction == $ordering_direction )
|
79 |
+
return '_order_' . $connection_direction;
|
80 |
+
|
81 |
+
if ( 'from' == $connection_direction )
|
82 |
+
return $ordering_direction;
|
83 |
+
|
84 |
+
return false;
|
85 |
+
}
|
86 |
+
|
87 |
+
static function get_ptype_label( $ptypes ) {
|
88 |
+
return get_post_type_object( $ptypes[0] )->labels->name;
|
89 |
+
}
|
90 |
+
|
91 |
+
static function expand_title( $title, $from, $to ) {
|
92 |
+
if ( !$title )
|
93 |
+
$title = array();
|
94 |
+
|
95 |
+
if ( $title && !is_array( $title ) ) {
|
96 |
+
return array(
|
97 |
+
'from' => $title,
|
98 |
+
'to' => $title,
|
99 |
+
);
|
100 |
+
}
|
101 |
+
|
102 |
+
foreach ( array( 'from', 'to' ) as $key ) {
|
103 |
+
if ( isset( $title[$key] ) )
|
104 |
+
continue;
|
105 |
+
|
106 |
+
$other_key = ( 'from' == $key ) ? 'to' : 'from';
|
107 |
+
|
108 |
+
$title[$key] = sprintf(
|
109 |
+
__( 'Connected %s', P2P_TEXTDOMAIN ),
|
110 |
+
P2P_Util::get_ptype_label( $$other_key )
|
111 |
+
);
|
112 |
+
}
|
113 |
+
|
114 |
+
return $title;
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
function _p2p_pluck( &$arr, $key ) {
|
119 |
+
$value = $arr[ $key ];
|
120 |
+
unset( $arr[ $key ] );
|
121 |
+
return $value;
|
122 |
+
}
|
123 |
+
|
core/widget.php
CHANGED
@@ -4,6 +4,7 @@ class P2P_Widget extends scbWidget {
|
|
4 |
|
5 |
protected $defaults = array(
|
6 |
'ctype' => false,
|
|
|
7 |
);
|
8 |
|
9 |
static function init( $file ) {
|
@@ -20,39 +21,59 @@ class P2P_Widget extends scbWidget {
|
|
20 |
if ( empty( $instance ) )
|
21 |
$instance = $this->defaults;
|
22 |
|
23 |
-
$ctypes = array_map( array( __CLASS__, 'ctype_label' ), P2P_Connection_Type::
|
24 |
|
25 |
-
echo $this->input( array(
|
26 |
'type' => 'select',
|
27 |
'name' => 'ctype',
|
28 |
'values' => $ctypes,
|
29 |
'desc' => __( 'Connection type:', P2P_TEXTDOMAIN )
|
30 |
-
), $instance );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
}
|
32 |
|
33 |
function widget( $args, $instance ) {
|
34 |
if ( !is_singular() )
|
35 |
return;
|
36 |
|
37 |
-
$
|
|
|
|
|
|
|
|
|
38 |
if ( !$ctype )
|
39 |
return;
|
40 |
|
41 |
-
$directed = $ctype->find_direction(
|
42 |
if ( !$directed )
|
43 |
return;
|
44 |
|
45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
if ( !$connected->have_posts() )
|
47 |
return;
|
48 |
|
49 |
-
$title = $directed->get_title();
|
50 |
-
|
51 |
-
if ( empty( $title ) ) {
|
52 |
-
$ptype = get_post_type_object( $directed->get_other_post_type() );
|
53 |
-
$title = sprintf( __( 'Related %s', P2P_TEXTDOMAIN ), $ptype->label );
|
54 |
-
}
|
55 |
-
|
56 |
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
|
57 |
|
58 |
extract( $args );
|
@@ -72,14 +93,14 @@ class P2P_Widget extends scbWidget {
|
|
72 |
$$key = implode( ', ', array_map( array( __CLASS__, 'post_type_label' ), $ctype->$key ) );
|
73 |
}
|
74 |
|
75 |
-
if ( $ctype->
|
76 |
$arrow = '↔';
|
77 |
else
|
78 |
$arrow = '→';
|
79 |
|
80 |
$label = "$from $arrow $to";
|
81 |
|
82 |
-
$title = $ctype->
|
83 |
|
84 |
if ( $title )
|
85 |
$label .= " ($title)";
|
4 |
|
5 |
protected $defaults = array(
|
6 |
'ctype' => false,
|
7 |
+
'listing' => 'connected'
|
8 |
);
|
9 |
|
10 |
static function init( $file ) {
|
21 |
if ( empty( $instance ) )
|
22 |
$instance = $this->defaults;
|
23 |
|
24 |
+
$ctypes = array_map( array( __CLASS__, 'ctype_label' ), P2P_Connection_Type::get_all_instances() );
|
25 |
|
26 |
+
echo html( 'p', $this->input( array(
|
27 |
'type' => 'select',
|
28 |
'name' => 'ctype',
|
29 |
'values' => $ctypes,
|
30 |
'desc' => __( 'Connection type:', P2P_TEXTDOMAIN )
|
31 |
+
), $instance ) );
|
32 |
+
|
33 |
+
echo html( 'p',
|
34 |
+
__( 'Connection listing:', P2P_TEXTDOMAIN ),
|
35 |
+
'<br>',
|
36 |
+
$this->input( array(
|
37 |
+
'type' => 'radio',
|
38 |
+
'name' => 'listing',
|
39 |
+
'values' => array(
|
40 |
+
'connected' => __( 'connected', P2P_TEXTDOMAIN ),
|
41 |
+
'related' => __( 'related', P2P_TEXTDOMAIN )
|
42 |
+
),
|
43 |
+
), $instance )
|
44 |
+
);
|
45 |
}
|
46 |
|
47 |
function widget( $args, $instance ) {
|
48 |
if ( !is_singular() )
|
49 |
return;
|
50 |
|
51 |
+
$instance = array_merge( $this->defaults, $instance );
|
52 |
+
|
53 |
+
$post_id = get_queried_object_id();
|
54 |
+
|
55 |
+
$ctype = p2p_type( $instance['ctype'] );
|
56 |
if ( !$ctype )
|
57 |
return;
|
58 |
|
59 |
+
$directed = $ctype->find_direction( $post_id );
|
60 |
if ( !$directed )
|
61 |
return;
|
62 |
|
63 |
+
if ( 'related' == $instance['listing'] ) {
|
64 |
+
$connected = $ctype->get_related( $post_id );
|
65 |
+
$title = sprintf(
|
66 |
+
__( 'Related %s', P2P_TEXTDOMAIN ),
|
67 |
+
P2P_Util::get_ptype_label( $directed->get_current_post_type() )
|
68 |
+
);
|
69 |
+
} else {
|
70 |
+
$connected = $directed->get_connected( $post_id );
|
71 |
+
$title = $directed->get_title();
|
72 |
+
}
|
73 |
+
|
74 |
if ( !$connected->have_posts() )
|
75 |
return;
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
|
78 |
|
79 |
extract( $args );
|
93 |
$$key = implode( ', ', array_map( array( __CLASS__, 'post_type_label' ), $ctype->$key ) );
|
94 |
}
|
95 |
|
96 |
+
if ( $ctype->indeterminate )
|
97 |
$arrow = '↔';
|
98 |
else
|
99 |
$arrow = '→';
|
100 |
|
101 |
$label = "$from $arrow $to";
|
102 |
|
103 |
+
$title = $ctype->set_direction( 'from' )->get_title();
|
104 |
|
105 |
if ( $title )
|
106 |
$label .= " ($title)";
|
lang/posts-to-posts-ro_RO.mo
CHANGED
Binary file
|
lang/posts-to-posts-ro_RO.po
CHANGED
@@ -7,85 +7,105 @@ msgid ""
|
|
7 |
msgstr ""
|
8 |
"Project-Id-Version: Posts 2 Posts\n"
|
9 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
10 |
-
"POT-Creation-Date: 2011-
|
11 |
-
"PO-Revision-Date: 2011-
|
12 |
-
"Last-Translator: scribu <scribu
|
13 |
"Language-Team: ROMANIAN <LL@li.org>\n"
|
14 |
"Language: \n"
|
15 |
"MIME-Version: 1.0\n"
|
16 |
"Content-Type: text/plain; charset=UTF-8\n"
|
17 |
"Content-Transfer-Encoding: 8bit\n"
|
18 |
|
19 |
-
#:
|
20 |
-
msgid "Settings <strong>saved</strong>."
|
21 |
-
msgstr "Setări <strong>salvate</strong>."
|
22 |
-
|
23 |
-
#: scb/AdminPage.php:176
|
24 |
-
#: scb/AdminPage.php:187
|
25 |
-
msgid "Save Changes"
|
26 |
-
msgstr "Salvează schimbările"
|
27 |
-
|
28 |
-
#: scb/AdminPage.php:348
|
29 |
-
msgid "Settings"
|
30 |
-
msgstr "Setări"
|
31 |
-
|
32 |
-
#: admin/fields.php:13
|
33 |
-
msgid "Create connection"
|
34 |
-
msgstr "Crează conexiune"
|
35 |
-
|
36 |
-
#: admin/fields.php:25
|
37 |
-
msgid "Delete all connections"
|
38 |
-
msgstr "Șterge toate conexiunile"
|
39 |
-
|
40 |
-
#: admin/fields.php:34
|
41 |
-
msgid "Delete connection"
|
42 |
-
msgstr "Șterge conexiune"
|
43 |
-
|
44 |
-
#: admin/box.php:59
|
45 |
msgid "Are you sure you want to delete all connections?"
|
46 |
msgstr "Sigur vreți să ștergeți toate conexiunile?"
|
47 |
|
48 |
-
#: admin/box.php:
|
49 |
-
msgid "Connected %s"
|
50 |
-
msgstr "%s conectate"
|
51 |
-
|
52 |
-
#: admin/box.php:116
|
53 |
msgid "Create connections:"
|
54 |
msgstr "Creează conexiuni:"
|
55 |
|
56 |
-
#: admin/box.php:
|
57 |
msgid "Search"
|
58 |
msgstr "Căutare"
|
59 |
|
60 |
-
#: admin/box.php:
|
61 |
msgid "View All"
|
62 |
msgstr "Vezi toate"
|
63 |
|
64 |
-
#: admin/box.php:
|
65 |
msgid "previous"
|
66 |
msgstr "anterioare"
|
67 |
|
68 |
-
#: admin/box.php:
|
69 |
msgid "next"
|
70 |
msgstr "următoare"
|
71 |
|
72 |
-
#: admin/box.php:
|
73 |
msgid "of"
|
74 |
msgstr "din"
|
75 |
|
76 |
-
#:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
msgid "Posts 2 Posts"
|
78 |
msgstr "Posts 2 Posts"
|
79 |
|
80 |
-
#: core/widget.php:
|
81 |
msgid "A list of posts connected to the current post"
|
82 |
msgstr "O lista de postări conectate la postarea curentă"
|
83 |
|
84 |
-
#: core/widget.php:
|
85 |
msgid "Connection type:"
|
86 |
msgstr "Tipul conexiunii:"
|
87 |
|
88 |
-
#: core/widget.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
msgid "Related %s"
|
90 |
msgstr "%s înrudite"
|
91 |
|
7 |
msgstr ""
|
8 |
"Project-Id-Version: Posts 2 Posts\n"
|
9 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
10 |
+
"POT-Creation-Date: 2011-11-13 13:52:29+00:00\n"
|
11 |
+
"PO-Revision-Date: 2011-11-13 15:54+0200\n"
|
12 |
+
"Last-Translator: scribu <mail@scribu.net>\n"
|
13 |
"Language-Team: ROMANIAN <LL@li.org>\n"
|
14 |
"Language: \n"
|
15 |
"MIME-Version: 1.0\n"
|
16 |
"Content-Type: text/plain; charset=UTF-8\n"
|
17 |
"Content-Transfer-Encoding: 8bit\n"
|
18 |
|
19 |
+
#: admin/box.php:74
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
msgid "Are you sure you want to delete all connections?"
|
21 |
msgstr "Sigur vreți să ștergeți toate conexiunile?"
|
22 |
|
23 |
+
#: admin/box.php:147
|
|
|
|
|
|
|
|
|
24 |
msgid "Create connections:"
|
25 |
msgstr "Creează conexiuni:"
|
26 |
|
27 |
+
#: admin/box.php:160
|
28 |
msgid "Search"
|
29 |
msgstr "Căutare"
|
30 |
|
31 |
+
#: admin/box.php:168
|
32 |
msgid "View All"
|
33 |
msgstr "Vezi toate"
|
34 |
|
35 |
+
#: admin/box.php:252
|
36 |
msgid "previous"
|
37 |
msgstr "anterioare"
|
38 |
|
39 |
+
#: admin/box.php:253
|
40 |
msgid "next"
|
41 |
msgstr "următoare"
|
42 |
|
43 |
+
#: admin/box.php:254
|
44 |
msgid "of"
|
45 |
msgstr "din"
|
46 |
|
47 |
+
#: admin/fields.php:16
|
48 |
+
msgid "Create connection"
|
49 |
+
msgstr "Crează conexiune"
|
50 |
+
|
51 |
+
#: admin/fields.php:30
|
52 |
+
msgid "Delete all connections"
|
53 |
+
msgstr "Șterge toate conexiunile"
|
54 |
+
|
55 |
+
#: admin/fields.php:39
|
56 |
+
msgid "Delete connection"
|
57 |
+
msgstr "Șterge conexiune"
|
58 |
+
|
59 |
+
#: scb/AdminPage.php:163
|
60 |
+
msgid "Settings <strong>saved</strong>."
|
61 |
+
msgstr "Setări <strong>salvate</strong>."
|
62 |
+
|
63 |
+
#: scb/AdminPage.php:176
|
64 |
+
#: scb/AdminPage.php:187
|
65 |
+
msgid "Save Changes"
|
66 |
+
msgstr "Salvează schimbările"
|
67 |
+
|
68 |
+
#: scb/AdminPage.php:348
|
69 |
+
msgid "Settings"
|
70 |
+
msgstr "Setări"
|
71 |
+
|
72 |
+
#: core/directed-type.php:59
|
73 |
+
msgid " (from)"
|
74 |
+
msgstr "(de la)"
|
75 |
+
|
76 |
+
#: core/directed-type.php:60
|
77 |
+
msgid " (to)"
|
78 |
+
msgstr "(la)"
|
79 |
+
|
80 |
+
#: core/type.php:86
|
81 |
+
msgid "Connected %s"
|
82 |
+
msgstr "%s conectate"
|
83 |
+
|
84 |
+
#: core/widget.php:15
|
85 |
msgid "Posts 2 Posts"
|
86 |
msgstr "Posts 2 Posts"
|
87 |
|
88 |
+
#: core/widget.php:16
|
89 |
msgid "A list of posts connected to the current post"
|
90 |
msgstr "O lista de postări conectate la postarea curentă"
|
91 |
|
92 |
+
#: core/widget.php:30
|
93 |
msgid "Connection type:"
|
94 |
msgstr "Tipul conexiunii:"
|
95 |
|
96 |
+
#: core/widget.php:34
|
97 |
+
msgid "Connection listing:"
|
98 |
+
msgstr "Tipul conexiunii:"
|
99 |
+
|
100 |
+
#: core/widget.php:40
|
101 |
+
msgid "connected"
|
102 |
+
msgstr "conectate"
|
103 |
+
|
104 |
+
#: core/widget.php:41
|
105 |
+
msgid "related"
|
106 |
+
msgstr "înrudite"
|
107 |
+
|
108 |
+
#: core/widget.php:66
|
109 |
msgid "Related %s"
|
110 |
msgstr "%s înrudite"
|
111 |
|
lang/posts-to-posts.pot
CHANGED
@@ -4,7 +4,7 @@ msgid ""
|
|
4 |
msgstr ""
|
5 |
"Project-Id-Version: \n"
|
6 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
7 |
-
"POT-Creation-Date: 2011-
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
@@ -12,74 +12,94 @@ msgstr ""
|
|
12 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
|
15 |
-
#:
|
16 |
-
msgid "
|
17 |
msgstr ""
|
18 |
|
19 |
-
#:
|
20 |
-
msgid "
|
21 |
msgstr ""
|
22 |
|
23 |
-
#:
|
24 |
-
msgid "
|
25 |
msgstr ""
|
26 |
|
27 |
-
#: admin/
|
28 |
-
msgid "
|
29 |
msgstr ""
|
30 |
|
31 |
-
#: admin/
|
32 |
-
msgid "
|
33 |
msgstr ""
|
34 |
|
35 |
-
#: admin/
|
36 |
-
msgid "
|
37 |
msgstr ""
|
38 |
|
39 |
-
#: admin/box.php:
|
40 |
-
msgid "
|
41 |
msgstr ""
|
42 |
|
43 |
-
#: admin/
|
44 |
-
msgid "
|
45 |
msgstr ""
|
46 |
|
47 |
-
#: admin/
|
48 |
-
msgid "
|
49 |
msgstr ""
|
50 |
|
51 |
-
#: admin/
|
52 |
-
msgid "
|
53 |
msgstr ""
|
54 |
|
55 |
-
#:
|
56 |
-
msgid "
|
57 |
msgstr ""
|
58 |
|
59 |
-
#:
|
60 |
-
msgid "
|
61 |
msgstr ""
|
62 |
|
63 |
-
#:
|
64 |
-
msgid "
|
65 |
msgstr ""
|
66 |
|
67 |
-
#:
|
68 |
-
msgid "
|
69 |
msgstr ""
|
70 |
|
71 |
-
#: core/
|
72 |
-
msgid "
|
|
|
|
|
|
|
|
|
73 |
msgstr ""
|
74 |
|
75 |
#: core/widget.php:15
|
|
|
|
|
|
|
|
|
76 |
msgid "A list of posts connected to the current post"
|
77 |
msgstr ""
|
78 |
|
79 |
-
#: core/widget.php:
|
80 |
msgid "Connection type:"
|
81 |
msgstr ""
|
82 |
|
83 |
-
#: core/widget.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
msgid "Related %s"
|
85 |
msgstr ""
|
4 |
msgstr ""
|
5 |
"Project-Id-Version: \n"
|
6 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
7 |
+
"POT-Creation-Date: 2011-11-13 13:52:29+00:00\n"
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
12 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
|
15 |
+
#: admin/box.php:74
|
16 |
+
msgid "Are you sure you want to delete all connections?"
|
17 |
msgstr ""
|
18 |
|
19 |
+
#: admin/box.php:147
|
20 |
+
msgid "Create connections:"
|
21 |
msgstr ""
|
22 |
|
23 |
+
#: admin/box.php:160
|
24 |
+
msgid "Search"
|
25 |
msgstr ""
|
26 |
|
27 |
+
#: admin/box.php:168
|
28 |
+
msgid "View All"
|
29 |
msgstr ""
|
30 |
|
31 |
+
#: admin/box.php:252
|
32 |
+
msgid "previous"
|
33 |
msgstr ""
|
34 |
|
35 |
+
#: admin/box.php:253
|
36 |
+
msgid "next"
|
37 |
msgstr ""
|
38 |
|
39 |
+
#: admin/box.php:254
|
40 |
+
msgid "of"
|
41 |
msgstr ""
|
42 |
|
43 |
+
#: admin/fields.php:16
|
44 |
+
msgid "Create connection"
|
45 |
msgstr ""
|
46 |
|
47 |
+
#: admin/fields.php:30
|
48 |
+
msgid "Delete all connections"
|
49 |
msgstr ""
|
50 |
|
51 |
+
#: admin/fields.php:39
|
52 |
+
msgid "Delete connection"
|
53 |
msgstr ""
|
54 |
|
55 |
+
#: scb/AdminPage.php:163
|
56 |
+
msgid "Settings <strong>saved</strong>."
|
57 |
msgstr ""
|
58 |
|
59 |
+
#: scb/AdminPage.php:176 scb/AdminPage.php:187
|
60 |
+
msgid "Save Changes"
|
61 |
msgstr ""
|
62 |
|
63 |
+
#: scb/AdminPage.php:348
|
64 |
+
msgid "Settings"
|
65 |
msgstr ""
|
66 |
|
67 |
+
#: core/directed-type.php:59
|
68 |
+
msgid " (from)"
|
69 |
msgstr ""
|
70 |
|
71 |
+
#: core/directed-type.php:60
|
72 |
+
msgid " (to)"
|
73 |
+
msgstr ""
|
74 |
+
|
75 |
+
#: core/type.php:86
|
76 |
+
msgid "Connected %s"
|
77 |
msgstr ""
|
78 |
|
79 |
#: core/widget.php:15
|
80 |
+
msgid "Posts 2 Posts"
|
81 |
+
msgstr ""
|
82 |
+
|
83 |
+
#: core/widget.php:16
|
84 |
msgid "A list of posts connected to the current post"
|
85 |
msgstr ""
|
86 |
|
87 |
+
#: core/widget.php:30
|
88 |
msgid "Connection type:"
|
89 |
msgstr ""
|
90 |
|
91 |
+
#: core/widget.php:34
|
92 |
+
msgid "Connection listing:"
|
93 |
+
msgstr ""
|
94 |
+
|
95 |
+
#: core/widget.php:40
|
96 |
+
msgid "connected"
|
97 |
+
msgstr ""
|
98 |
+
|
99 |
+
#: core/widget.php:41
|
100 |
+
msgid "related"
|
101 |
+
msgstr ""
|
102 |
+
|
103 |
+
#: core/widget.php:66
|
104 |
msgid "Related %s"
|
105 |
msgstr ""
|
mustache/Mustache.php
CHANGED
@@ -14,7 +14,8 @@
|
|
14 |
*/
|
15 |
class Mustache {
|
16 |
|
17 |
-
const VERSION
|
|
|
18 |
|
19 |
/**
|
20 |
* Should this Mustache throw exceptions when it finds unexpected tags?
|
@@ -238,7 +239,10 @@ class Mustache {
|
|
238 |
|
239 |
// regular section
|
240 |
case '#':
|
241 |
-
|
|
|
|
|
|
|
242 |
foreach ($val as $local_context) {
|
243 |
$this->_pushContext($local_context);
|
244 |
$rendered_content .= $this->_renderTemplate($content);
|
@@ -615,7 +619,8 @@ class Mustache {
|
|
615 |
* @return string
|
616 |
*/
|
617 |
protected function _renderEscaped($tag_name, $leading, $trailing) {
|
618 |
-
|
|
|
619 |
}
|
620 |
|
621 |
/**
|
@@ -647,7 +652,13 @@ class Mustache {
|
|
647 |
* @return string
|
648 |
*/
|
649 |
protected function _renderUnescaped($tag_name, $leading, $trailing) {
|
650 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
651 |
}
|
652 |
|
653 |
/**
|
@@ -808,7 +819,10 @@ class Mustache {
|
|
808 |
* @return string
|
809 |
*/
|
810 |
protected function _getPartial($tag_name) {
|
811 |
-
if (
|
|
|
|
|
|
|
812 |
return $this->_partials[$tag_name];
|
813 |
}
|
814 |
|
@@ -829,6 +843,23 @@ class Mustache {
|
|
829 |
protected function _varIsIterable($var) {
|
830 |
return $var instanceof Traversable || (is_array($var) && !array_diff_key($var, array_keys(array_keys($var))));
|
831 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
832 |
}
|
833 |
|
834 |
|
@@ -859,4 +890,3 @@ class MustacheException extends Exception {
|
|
859 |
const UNKNOWN_PRAGMA = 4;
|
860 |
|
861 |
}
|
862 |
-
|
14 |
*/
|
15 |
class Mustache {
|
16 |
|
17 |
+
const VERSION = '0.8.0';
|
18 |
+
const SPEC_VERSION = '1.1.2';
|
19 |
|
20 |
/**
|
21 |
* Should this Mustache throw exceptions when it finds unexpected tags?
|
239 |
|
240 |
// regular section
|
241 |
case '#':
|
242 |
+
// higher order sections
|
243 |
+
if ($this->_varIsCallable($val)) {
|
244 |
+
$rendered_content = $this->_renderTemplate(call_user_func($val, $content));
|
245 |
+
} else if ($this->_varIsIterable($val)) {
|
246 |
foreach ($val as $local_context) {
|
247 |
$this->_pushContext($local_context);
|
248 |
$rendered_content .= $this->_renderTemplate($content);
|
619 |
* @return string
|
620 |
*/
|
621 |
protected function _renderEscaped($tag_name, $leading, $trailing) {
|
622 |
+
$rendered = htmlentities($this->_renderUnescaped($tag_name, '', ''), ENT_COMPAT, $this->_charset);
|
623 |
+
return $leading . $rendered . $trailing;
|
624 |
}
|
625 |
|
626 |
/**
|
652 |
* @return string
|
653 |
*/
|
654 |
protected function _renderUnescaped($tag_name, $leading, $trailing) {
|
655 |
+
$val = $this->_getVariable($tag_name);
|
656 |
+
|
657 |
+
if ($this->_varIsCallable($val)) {
|
658 |
+
$val = $this->_renderTemplate(call_user_func($val));
|
659 |
+
}
|
660 |
+
|
661 |
+
return $leading . $val . $trailing;
|
662 |
}
|
663 |
|
664 |
/**
|
819 |
* @return string
|
820 |
*/
|
821 |
protected function _getPartial($tag_name) {
|
822 |
+
if (
|
823 |
+
(is_array($this->_partials) || $this->_partials instanceof ArrayAccess)
|
824 |
+
&& isset($this->_partials[$tag_name])
|
825 |
+
) {
|
826 |
return $this->_partials[$tag_name];
|
827 |
}
|
828 |
|
843 |
protected function _varIsIterable($var) {
|
844 |
return $var instanceof Traversable || (is_array($var) && !array_diff_key($var, array_keys(array_keys($var))));
|
845 |
}
|
846 |
+
|
847 |
+
/**
|
848 |
+
* Higher order sections helper: tests whether the section $var is a valid callback.
|
849 |
+
*
|
850 |
+
* In Mustache.php, a variable is considered 'callable' if the variable is:
|
851 |
+
*
|
852 |
+
* 1. an anonymous function.
|
853 |
+
* 2. an object and the name of a public function, i.e. `array($SomeObject, 'methodName')`
|
854 |
+
* 3. a class name and the name of a public static function, i.e. `array('SomeClass', 'methodName')`
|
855 |
+
*
|
856 |
+
* @access protected
|
857 |
+
* @param mixed $var
|
858 |
+
* @return bool
|
859 |
+
*/
|
860 |
+
protected function _varIsCallable($var) {
|
861 |
+
return !is_string($var) && is_callable($var);
|
862 |
+
}
|
863 |
}
|
864 |
|
865 |
|
890 |
const UNKNOWN_PRAGMA = 4;
|
891 |
|
892 |
}
|
|
mustache/MustacheLoader.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A Mustache Partial filesystem loader.
|
5 |
+
*
|
6 |
+
* @author Justin Hileman {@link http://justinhileman.com}
|
7 |
+
*/
|
8 |
+
class MustacheLoader implements ArrayAccess {
|
9 |
+
|
10 |
+
protected $baseDir;
|
11 |
+
protected $partialsCache = array();
|
12 |
+
protected $extension;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* MustacheLoader constructor.
|
16 |
+
*
|
17 |
+
* @access public
|
18 |
+
* @param string $baseDir Base template directory.
|
19 |
+
* @param string $extension File extension for Mustache files (default: 'mustache')
|
20 |
+
* @return void
|
21 |
+
*/
|
22 |
+
public function __construct($baseDir, $extension = 'mustache') {
|
23 |
+
if (!is_dir($baseDir)) {
|
24 |
+
throw new InvalidArgumentException('$baseDir must be a valid directory, ' . $baseDir . ' given.');
|
25 |
+
}
|
26 |
+
|
27 |
+
$this->baseDir = $baseDir;
|
28 |
+
$this->extension = $extension;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param string $offset Name of partial
|
33 |
+
* @return boolean
|
34 |
+
*/
|
35 |
+
public function offsetExists($offset) {
|
36 |
+
return (isset($this->partialsCache[$offset]) || file_exists($this->pathName($offset)));
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* @throws InvalidArgumentException if the given partial doesn't exist
|
41 |
+
* @param string $offset Name of partial
|
42 |
+
* @return string Partial template contents
|
43 |
+
*/
|
44 |
+
public function offsetGet($offset) {
|
45 |
+
if (!$this->offsetExists($offset)) {
|
46 |
+
throw new InvalidArgumentException('Partial does not exist: ' . $offset);
|
47 |
+
}
|
48 |
+
|
49 |
+
if (!isset($this->partialsCache[$offset])) {
|
50 |
+
$this->partialsCache[$offset] = file_get_contents($this->pathName($offset));
|
51 |
+
}
|
52 |
+
|
53 |
+
return $this->partialsCache[$offset];
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* MustacheLoader is an immutable filesystem loader. offsetSet throws a LogicException if called.
|
58 |
+
*
|
59 |
+
* @throws LogicException
|
60 |
+
* @return void
|
61 |
+
*/
|
62 |
+
public function offsetSet($offset, $value) {
|
63 |
+
throw new LogicException('Unable to set offset: MustacheLoader is an immutable ArrayAccess object.');
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* MustacheLoader is an immutable filesystem loader. offsetUnset throws a LogicException if called.
|
68 |
+
*
|
69 |
+
* @throws LogicException
|
70 |
+
* @return void
|
71 |
+
*/
|
72 |
+
public function offsetUnset($offset) {
|
73 |
+
throw new LogicException('Unable to unset offset: MustacheLoader is an immutable ArrayAccess object.');
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* An internal helper for generating path names.
|
78 |
+
*
|
79 |
+
* @param string $file Partial name
|
80 |
+
* @return string File path
|
81 |
+
*/
|
82 |
+
protected function pathName($file) {
|
83 |
+
return $this->baseDir . '/' . $file . '.' . $this->extension;
|
84 |
+
}
|
85 |
+
}
|
posts-to-posts.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
/*
|
3 |
Plugin Name: Posts 2 Posts
|
4 |
Description: Create many-to-many relationships between all types of posts.
|
5 |
-
Version: 0.
|
6 |
Author: scribu
|
7 |
Author URI: http://scribu.net/
|
8 |
Plugin URI: http://scribu.net/wordpress/posts-to-posts
|
@@ -10,7 +10,7 @@ Text Domain: posts-to-posts
|
|
10 |
Domain Path: /lang
|
11 |
|
12 |
|
13 |
-
Copyright (C) 2010-2011 Cristi Burcă (scribu
|
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
|
@@ -26,7 +26,7 @@ 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_PLUGIN_VERSION', '0.
|
30 |
|
31 |
define( 'P2P_TEXTDOMAIN', 'posts-to-posts' );
|
32 |
|
@@ -37,22 +37,27 @@ function _p2p_init() {
|
|
37 |
|
38 |
load_plugin_textdomain( P2P_TEXTDOMAIN, '', basename( $base ) . '/lang' );
|
39 |
|
40 |
-
|
41 |
-
|
|
|
|
|
|
|
42 |
|
43 |
P2P_Widget::init( __FILE__ );
|
44 |
|
45 |
if ( is_admin() ) {
|
46 |
-
|
47 |
-
|
|
|
|
|
|
|
48 |
}
|
49 |
}
|
50 |
scb_init( '_p2p_init' );
|
51 |
|
52 |
-
function _p2p_append( &$arr, $values ) {
|
53 |
-
if ( !is_array( $arr ) )
|
54 |
-
$arr = array();
|
55 |
|
56 |
-
|
|
|
|
|
57 |
}
|
58 |
|
2 |
/*
|
3 |
Plugin Name: Posts 2 Posts
|
4 |
Description: Create many-to-many relationships between all types of posts.
|
5 |
+
Version: 1.0.1
|
6 |
Author: scribu
|
7 |
Author URI: http://scribu.net/
|
8 |
Plugin URI: http://scribu.net/wordpress/posts-to-posts
|
10 |
Domain Path: /lang
|
11 |
|
12 |
|
13 |
+
Copyright (C) 2010-2011 Cristi Burcă (mail@scribu.net)
|
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
|
26 |
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
27 |
*/
|
28 |
|
29 |
+
define( 'P2P_PLUGIN_VERSION', '1.0.1' );
|
30 |
|
31 |
define( 'P2P_TEXTDOMAIN', 'posts-to-posts' );
|
32 |
|
37 |
|
38 |
load_plugin_textdomain( P2P_TEXTDOMAIN, '', basename( $base ) . '/lang' );
|
39 |
|
40 |
+
_p2p_load_files( "$base/core", array(
|
41 |
+
'storage', 'query', 'url-query',
|
42 |
+
'util', 'type', 'directed-type', 'ordered-type',
|
43 |
+
'api', 'widget'
|
44 |
+
) );
|
45 |
|
46 |
P2P_Widget::init( __FILE__ );
|
47 |
|
48 |
if ( is_admin() ) {
|
49 |
+
_p2p_load_files( "$base/admin", array(
|
50 |
+
'utils',
|
51 |
+
'box-factory', 'box', 'fields',
|
52 |
+
'column-factory', 'column'
|
53 |
+
) );
|
54 |
}
|
55 |
}
|
56 |
scb_init( '_p2p_init' );
|
57 |
|
|
|
|
|
|
|
58 |
|
59 |
+
function _p2p_load_files( $dir, $files ) {
|
60 |
+
foreach ( $files as $file )
|
61 |
+
require_once "$dir/$file.php";
|
62 |
}
|
63 |
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: scribu, ciobi
|
|
3 |
Tags: cms, custom post types, relationships, many-to-many
|
4 |
Requires at least: 3.2
|
5 |
Tested up to: 3.3
|
6 |
-
Stable tag: 0.
|
7 |
|
8 |
Create connections between posts
|
9 |
|
@@ -13,8 +13,9 @@ This plugin allows you to create many-to-many relationships between posts of any
|
|
13 |
|
14 |
A few example use cases:
|
15 |
|
16 |
-
*
|
17 |
* manually curated lists of related posts
|
|
|
18 |
|
19 |
etc.
|
20 |
|
@@ -41,9 +42,29 @@ Make sure your host is running PHP 5. The only foolproof way to do this is to ad
|
|
41 |
|
42 |
1. Basic connection metabox
|
43 |
2. Advanced connection metabox
|
|
|
|
|
44 |
|
45 |
== Changelog ==
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
= 0.9.5 =
|
48 |
* add '{from|to}_query_vars' args to p2p_register_connection_type()
|
49 |
* add 'cardinality' arg to p2p_register_connection_type()
|
3 |
Tags: cms, custom post types, relationships, many-to-many
|
4 |
Requires at least: 3.2
|
5 |
Tested up to: 3.3
|
6 |
+
Stable tag: 1.0.1
|
7 |
|
8 |
Create connections between posts
|
9 |
|
13 |
|
14 |
A few example use cases:
|
15 |
|
16 |
+
* post series
|
17 |
* manually curated lists of related posts
|
18 |
+
* 'actor' posts connected to 'movie' posts
|
19 |
|
20 |
etc.
|
21 |
|
42 |
|
43 |
1. Basic connection metabox
|
44 |
2. Advanced connection metabox
|
45 |
+
3. Admin column
|
46 |
+
4. Widget
|
47 |
|
48 |
== Changelog ==
|
49 |
|
50 |
+
= 1.0.1 =
|
51 |
+
* don't show metabox at all if user doesn't have the required capability
|
52 |
+
* fix checkbox handling when there are no other input fields
|
53 |
+
* improve metabox styling
|
54 |
+
* rename 'show_ui' to 'admin_box'
|
55 |
+
* add 'admin_column' parameter
|
56 |
+
|
57 |
+
= 1.0 =
|
58 |
+
* widget can now list related posts
|
59 |
+
* add P2P_Connection_Type::get_related() method
|
60 |
+
* add 'can_create_post' arg to p2p_register_connection_type()
|
61 |
+
* two-box mode for `'reciprocal' => false`
|
62 |
+
* more options for 'show_ui'
|
63 |
+
* allow checkboxes, radio buttons and textareas as connection fields
|
64 |
+
* allow drag & drop ordering in both directions
|
65 |
+
* added get_previous(), get_next() and get_adjacent() methods to P2P_Connection_Type
|
66 |
+
* [more info](http://scribu.net/wordpress/posts-to-posts/p2p-1-0.html)
|
67 |
+
|
68 |
= 0.9.5 =
|
69 |
* add '{from|to}_query_vars' args to p2p_register_connection_type()
|
70 |
* add 'cardinality' arg to p2p_register_connection_type()
|
scb/BoxesPage.php
CHANGED
@@ -25,8 +25,6 @@ abstract class scbBoxesPage extends scbAdminPage {
|
|
25 |
parent::page_init();
|
26 |
|
27 |
add_action( 'load-' . $this->pagehook, array( $this, 'boxes_init' ) );
|
28 |
-
|
29 |
-
add_screen_option( 'layout_columns', array( 'max' => $this->args['columns'], 'default' => $this->args['columns'] ) );
|
30 |
}
|
31 |
|
32 |
function default_css() {
|
@@ -163,6 +161,11 @@ abstract class scbBoxesPage extends scbAdminPage {
|
|
163 |
function boxes_init() {
|
164 |
wp_enqueue_script( 'postbox' );
|
165 |
|
|
|
|
|
|
|
|
|
|
|
166 |
$registered = array();
|
167 |
foreach( $this->boxes as $box_args ) {
|
168 |
@list( $name, $title, $context, $priority, $args ) = $box_args;
|
25 |
parent::page_init();
|
26 |
|
27 |
add_action( 'load-' . $this->pagehook, array( $this, 'boxes_init' ) );
|
|
|
|
|
28 |
}
|
29 |
|
30 |
function default_css() {
|
161 |
function boxes_init() {
|
162 |
wp_enqueue_script( 'postbox' );
|
163 |
|
164 |
+
add_screen_option( 'layout_columns', array(
|
165 |
+
'max' => $this->args['columns'],
|
166 |
+
'default' => $this->args['columns']
|
167 |
+
) );
|
168 |
+
|
169 |
$registered = array();
|
170 |
foreach( $this->boxes as $box_args ) {
|
171 |
@list( $name, $title, $context, $priority, $args ) = $box_args;
|
scb/Forms.php
CHANGED
@@ -373,13 +373,14 @@ class scbForms {
|
|
373 |
*
|
374 |
* @param array|string $name The name of the value
|
375 |
* @param array $value The data that will be traversed
|
|
|
376 |
*
|
377 |
* @return mixed
|
378 |
*/
|
379 |
-
static function get_value( $name, $value ) {
|
380 |
foreach ( (array) $name as $key ) {
|
381 |
if ( !isset( $value[ $key ] ) )
|
382 |
-
return
|
383 |
|
384 |
$value = $value[$key];
|
385 |
}
|
373 |
*
|
374 |
* @param array|string $name The name of the value
|
375 |
* @param array $value The data that will be traversed
|
376 |
+
* @param mixed $fallback The value returned when the key is not found
|
377 |
*
|
378 |
* @return mixed
|
379 |
*/
|
380 |
+
static function get_value( $name, $value, $fallback = null ) {
|
381 |
foreach ( (array) $name as $key ) {
|
382 |
if ( !isset( $value[ $key ] ) )
|
383 |
+
return $fallback;
|
384 |
|
385 |
$value = $value[$key];
|
386 |
}
|
scb/load.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
$GLOBALS['_scb_data'] = array(
|
4 |
'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
|
5 |
'scbWidget', 'scbAdminPage', 'scbBoxesPage',
|
6 |
'scbCron', 'scbHooks',
|
1 |
<?php
|
2 |
|
3 |
+
$GLOBALS['_scb_data'] = array( 42, __FILE__, array(
|
4 |
'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
|
5 |
'scbWidget', 'scbAdminPage', 'scbBoxesPage',
|
6 |
'scbCron', 'scbHooks',
|
screenshot-1.png
CHANGED
Binary file
|
screenshot-2.png
CHANGED
Binary file
|
screenshot-3.png
ADDED
Binary file
|
screenshot-4.png
ADDED
Binary file
|