Skip to content

Commit 0a2d0eb

Browse files
committed
Merge pull request #374 from alleyinteractive/enhance-context-actions
Improve flexibility of context actions
2 parents bad3343 + 8ad9f49 commit 0a2d0eb

File tree

2 files changed

+125
-14
lines changed

2 files changed

+125
-14
lines changed

fieldmanager.php

+25-14
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,15 @@ function _fieldmanager_registry( $var, $val = null ) {
243243
*
244244
* @see fm_calculate_context() for detail about the returned array values.
245245
*
246+
* @param bool $recalculate Optional. If true, FM will recalculate the current
247+
* context. This is necessary for testing and perhaps
248+
* other programmatic purposes.
246249
* @return array Contextual information for the current request.
247250
*/
248-
function fm_get_context() {
251+
function fm_get_context( $recalculate = false ) {
249252
static $calculated_context;
250253

251-
if ( $calculated_context ) {
254+
if ( ! $recalculate && $calculated_context ) {
252255
return $calculated_context;
253256
} else {
254257
$calculated_context = fm_calculate_context();
@@ -408,30 +411,38 @@ function fm_match_context( $context, $type = null ) {
408411
*/
409412
function fm_trigger_context_action() {
410413
$calculated_context = fm_get_context();
411-
if ( empty( $calculated_context ) ) {
414+
if ( empty( $calculated_context[0] ) ) {
412415
return;
413416
}
414417

415-
$context = $calculated_context[0];
416-
if ( $type = $calculated_context[1] ) {
418+
list( $context, $type ) = $calculated_context;
419+
420+
if ( $type ) {
417421
/**
418422
* Fires when a specific Fieldmanager context and type load.
419423
*
420424
* The dynamic portions of the hook name, $context and $type, refer to
421425
* the values returned by fm_calculate_context(). For example, the Edit
422426
* screen for the Page post type would fire "fm_post_page".
423-
*/
424-
do_action( "fm_{$context}_{$type}" );
425-
} else {
426-
/**
427-
* Fires when a specific Fieldmanager context, but not type, loads.
428427
*
429-
* The dynamic portion of the hook name, $context, refers to the first
430-
* value returned by fm_calculate_context(). For example, the Edit User
431-
* screen would fire "fm_user".
428+
* @param string $type The context subtype, e.g. the post type, taxonomy
429+
* name, submenu option name.
432430
*/
433-
do_action( "fm_{$context}" );
431+
do_action( "fm_{$context}_{$type}", $type );
434432
}
433+
434+
/**
435+
* Fires when any Fieldmanager context loads.
436+
*
437+
* The dynamic portion of the hook name, $context, refers to the first
438+
* value returned by fm_calculate_context(). For example, the Edit User
439+
* screen would fire "fm_user".
440+
*
441+
* @param string|null $type The context subtype, e.g. the post type,
442+
* taxonomy name, submenu option name. null if this
443+
* context does not have a subtype.
444+
*/
445+
do_action( "fm_{$context}", $type );
435446
}
436447
add_action( 'init', 'fm_trigger_context_action', 99 );
437448

tests/php/test-fieldmanager-calculate-context.php

+100
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class Test_Fieldmanager_Calculate_Context extends WP_UnitTestCase {
88
protected $screen, $self, $get, $submenus;
99

1010
public function setUp() {
11+
parent::setUp();
12+
1113
$this->screen = get_current_screen();
1214
$this->self = isset( $_SERVER['PHP_SELF'] ) ? $_SERVER['PHP_SELF'] : null;
1315
$this->get = $_GET;
@@ -24,6 +26,47 @@ public function tearDown( $value = null ) {
2426
$_SERVER['PHP_SELF'] = $this->self;
2527
$_GET = $this->get;
2628
_fieldmanager_registry( 'submenus', $this->submenus );
29+
30+
parent::tearDown();
31+
}
32+
33+
/**
34+
* Test arbitrary context actions given a context and type.
35+
*
36+
* @param string $context The context being tested.
37+
* @param string $type The subcontext being tested.
38+
*/
39+
protected function _context_action_assertions( $context, $type ) {
40+
$a = new MockAction();
41+
42+
if ( $context ) {
43+
add_action( "fm_{$context}", array( &$a, 'action' ) );
44+
}
45+
if ( $type ) {
46+
add_action( "fm_{$context}_{$type}", array( &$a, 'action' ) );
47+
}
48+
49+
fm_get_context( true );
50+
fm_trigger_context_action();
51+
52+
if ( $type ) {
53+
// only two events occurred for the hook
54+
$this->assertEquals( 2, $a->get_call_count() );
55+
// only our hooks were called
56+
$this->assertEquals( array( "fm_{$context}_{$type}", "fm_{$context}" ), $a->get_tags() );
57+
// The $type should have been passed as args
58+
$this->assertEquals( array( array( $type ), array( $type ) ), $a->get_args() );
59+
} elseif ( $context ) {
60+
// only one event occurred for the hook
61+
$this->assertEquals( 1, $a->get_call_count() );
62+
// only our hook was called
63+
$this->assertEquals( array( "fm_{$context}" ), $a->get_tags() );
64+
// null should have been passed as an arg
65+
$this->assertEquals( array( array( null ) ), $a->get_args() );
66+
} else {
67+
// No event should have fired
68+
$this->assertEquals( 0, $a->get_call_count() );
69+
}
2770
}
2871

2972
/**
@@ -69,6 +112,7 @@ public function test_submenu_contexts( $parent, $php_self = null ) {
69112
}
70113
$_GET['page'] = $submenu;
71114
$this->assertEquals( array( 'submenu', $submenu ), fm_calculate_context() );
115+
$this->_context_action_assertions( 'submenu', $submenu );
72116
}
73117

74118
/**
@@ -78,5 +122,61 @@ public function test_non_fm_submenu() {
78122
$_SERVER['PHP_SELF'] = '/themes.php';
79123
$_GET['page'] = rand_str();
80124
$this->assertEquals( array( null, null ), fm_calculate_context() );
125+
$this->_context_action_assertions( null, null );
126+
}
127+
128+
/**
129+
* Provide data for test_basic_contexts.
130+
*
131+
* @see https://phpunit.de/manual/4.7/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers
132+
*
133+
* @return array
134+
*/
135+
public function basic_contexts_args() {
136+
return array(
137+
array( '/post-new.php', array( 'post_type' => 'page' ), 'post', 'page' ),
138+
array( '/profile.php', null, 'user', null ),
139+
array( '/user-edit.php', null, 'user', null ),
140+
array( '/edit.php', array( 'post_type' => 'page' ), 'quickedit', 'page' ),
141+
array( '/edit-tags.php', array( 'taxonomy' => 'category' ), 'term', 'category' ),
142+
);
143+
}
144+
145+
/**
146+
* Test context calculations for assorted contexts.
147+
*
148+
* @dataProvider basic_contexts_args
149+
*/
150+
public function test_basic_contexts( $self_override, $get_override, $context, $type ) {
151+
$_SERVER['PHP_SELF'] = $self_override;
152+
$_GET = $get_override;
153+
$this->assertEquals( array( $context, $type ), fm_calculate_context() );
154+
$this->_context_action_assertions( $context, $type );
155+
}
156+
157+
public function test_post_screen_context() {
158+
$_SERVER['PHP_SELF'] = '/post.php';
159+
$post_id = $this->factory->post->create( array( 'post_title' => rand_str(), 'post_date' => '2015-07-01 00:00:00', 'post_type' => 'page' ) );
160+
$_GET = array( 'post' => strval( $post_id ) );
161+
$this->assertEquals( array( 'post', 'page' ), fm_calculate_context() );
162+
$this->_context_action_assertions( 'post', 'page' );
163+
}
164+
165+
public function test_post_save_screen_context() {
166+
$_SERVER['PHP_SELF'] = '/post.php';
167+
$_POST = array( 'action' => 'editpost', 'post_type' => 'page' );
168+
$this->assertEquals( array( 'post', 'page' ), fm_calculate_context() );
169+
$this->_context_action_assertions( 'post', 'page' );
170+
}
171+
172+
public function test_ajax_direct_context() {
173+
$_SERVER['PHP_SELF'] = '/admin-ajax.php';
174+
$_POST = array( 'fm_context' => 'foo' );
175+
$this->assertEquals( array( 'foo', null ), fm_calculate_context() );
176+
$this->_context_action_assertions( 'foo', null );
177+
178+
$_POST = array( 'fm_context' => 'foo', 'fm_subcontext' => 'bar' );
179+
$this->assertEquals( array( 'foo', 'bar' ), fm_calculate_context() );
180+
$this->_context_action_assertions( 'foo', 'bar' );
81181
}
82182
}

0 commit comments

Comments
 (0)