Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions classes/helpers/FrmEntriesListHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -390,11 +390,12 @@ public function single_row( $item, $style = '' ) {
if ( $this->column_name === 'cb' ) {
$r .= "<th scope='row' class='check-column'>$checkbox</th>";
} else {
$val = in_array( $column_name, $hidden, true ) ? '' : $this->column_value( $item );
$r .= "<td $attributes>";

// phpcs:ignore Universal.Operators.StrictComparisons
if ( $column_name == $action_col ) {
$is_action_col = $column_name == $action_col;
$val = in_array( $column_name, $hidden, true ) ? '' : $this->column_value( $item, $is_action_col );
$r .= "<td $attributes>";

if ( $is_action_col ) {
$edit_link = admin_url( 'admin.php?page=formidable-entries&frm_action=edit&id=' . $item->id );
$r .= '<a href="' . esc_url( isset( $actions['edit'] ) ? $edit_link : $view_link ) . '" class="row-title" >' . $val . '</a> ';
$r .= $action_links;
Expand All @@ -420,10 +421,12 @@ private function get_action_columns() {

/**
* @param object $item
* @param bool $is_action_col Whether this column is the row's primary/action column
* (wrapped in the row-title link by the caller).
*
* @return mixed
*/
private function column_value( $item ) {
private function column_value( $item, $is_action_col = false ) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`column_value` has a cyclomatic complexity of 18 with "High" risk


A function with high cyclomatic complexity can be hard to understand and
maintain. Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A higher cyclomatic complexity indicates
that the function has more decision points and is more complex.

$col_name = $this->maybe_fix_column_name( $this->column_name );

switch ( $col_name ) {
Expand Down Expand Up @@ -452,14 +455,27 @@ private function column_value( $item ) {
$form_id = $item->form_id;
$user_can_edit_forms = false === FrmAppHelper::permission_nonce_error( 'frm_edit_forms' );

if ( $user_can_edit_forms ) {
if ( $user_can_edit_forms && ! $is_action_col ) {
// When this column is the row's own action column, the caller already
// wraps it in a row-title link to the entry -- nesting a second <a> here
// (to the form itself) produces invalid, empty-named markup once the
// browser closes the outer anchor early. Fall back to the plain label,
// same as when the user can't edit forms.
$val = FrmFormsHelper::edit_form_link( $form_id );
} else {
$val = FrmFormsHelper::edit_form_link_label( $form_id );
}
break;
case 'post_id':
$val = FrmAppHelper::post_edit_link( $item->post_id );
if ( $is_action_col ) {
// Same reasoning as the form_id case above: post_edit_link() builds its
// own nested <a>, which breaks the outer row-title link when this column
// is the action column.
$post = get_post( $item->post_id );
$val = $post ? FrmAppHelper::truncate( $post->post_title, 50 ) : FrmFormsHelper::get_no_title_text();
} else {
$val = FrmAppHelper::post_edit_link( $item->post_id );
}
break;
case 'user_id':
$user = get_userdata( $item->user_id );
Expand Down
95 changes: 93 additions & 2 deletions tests/phpunit/entries/test_FrmEntriesListHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,104 @@ public function test_column_value() {
$this->assertSame( 'My entry name', $column_value );
}

/**
* The Form column's own value is wrapped in a second, nested row-title
* link when it's the row's action column (e.g. Entry Key/ID columns
* hidden on the "all forms" Entries screen) -- browsers implicitly close
* the outer row-title <a> as soon as they hit that nested one, leaving it
* with no accessible name. When acting as the action column, the form
* value must be plain text instead.
*
* @covers FrmEntriesListHelper::column_value
*/
public function test_column_value_form_id_as_action_col_has_no_nested_link() {
FrmAppHelper::set_current_screen_and_hook_suffix();
wp_set_current_user( 1 );

$item = new stdClass();
$item->form_id = $this->factory->form->create( array( 'name' => 'My Form' ) );

// Not the action column: existing behavior, links to the form itself.
$column_value = $this->column_value( $item, 'form_id', false );
$this->assertStringContainsString( '<a ', $column_value );
$this->assertStringContainsString( 'My Form', $column_value );

// As the action column: no nested <a>, plain label only.
$column_value = $this->column_value( $item, 'form_id', true );
$this->assertStringNotContainsString( '<a ', $column_value );
$this->assertSame( 'My Form', $column_value );
}

/**
* An entry whose form no longer exists (form_id doesn't resolve to a
* row) must still render non-empty fallback text as the action column,
* not an empty row-title link.
*
* @covers FrmEntriesListHelper::column_value
*/
public function test_column_value_form_id_as_action_col_missing_form_falls_back() {
FrmAppHelper::set_current_screen_and_hook_suffix();
wp_set_current_user( 1 );

$item = new stdClass();
$item->form_id = 999999999;

$column_value = $this->column_value( $item, 'form_id', true );
$this->assertNotEmpty( $column_value );
$this->assertStringNotContainsString( '<a ', $column_value );
}

/**
* Same bug class as the form_id case above, on the Post column shown
* when a form has a create-post action: post_edit_link() builds its own
* nested <a>, which must be dropped in favor of a plain label when this
* column is the row's action column.
*
* @covers FrmEntriesListHelper::column_value
*/
public function test_column_value_post_id_as_action_col_has_no_nested_link() {
FrmAppHelper::set_current_screen_and_hook_suffix();

$item = new stdClass();
$item->post_id = $this->factory->post->create( array( 'post_title' => 'My Post' ) );

// Not the action column: existing behavior, links to the post itself.
$column_value = $this->column_value( $item, 'post_id', false );
$this->assertStringContainsString( '<a ', $column_value );
$this->assertStringContainsString( 'My Post', $column_value );

// As the action column: no nested <a>, plain label only.
$column_value = $this->column_value( $item, 'post_id', true );
$this->assertStringNotContainsString( '<a ', $column_value );
$this->assertSame( 'My Post', $column_value );
}

/**
* An entry whose linked post no longer exists must still render
* non-empty fallback text as the action column, not an empty
* row-title link.
*
* @covers FrmEntriesListHelper::column_value
*/
public function test_column_value_post_id_as_action_col_missing_post_falls_back() {
FrmAppHelper::set_current_screen_and_hook_suffix();

$item = new stdClass();
$item->post_id = 999999999;

$column_value = $this->column_value( $item, 'post_id', true );
$this->assertNotEmpty( $column_value );
$this->assertStringNotContainsString( '<a ', $column_value );
}

/**
* @param stdClass $item
* @param string $column_name
* @param bool $is_action_col
*/
private function column_value( $item, $column_name ) {
private function column_value( $item, $column_name, $is_action_col = false ) {
$list_helper = new FrmEntriesListHelper( array() );
$this->set_private_property( $list_helper, 'column_name', $column_name );
return $this->run_private_method( array( $list_helper, 'column_value' ), array( $item ) );
return $this->run_private_method( array( $list_helper, 'column_value' ), array( $item, $is_action_col ) );
}
}
Loading