Skip to content
Merged
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
25 changes: 25 additions & 0 deletions classes/class-aal-export.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public function admin_capture_action( $list_table ) {
$list_table->prepare_items();
$items = $list_table->items;
$columns = $list_table->get_columns();
$columns = $this->add_export_ip_column( $columns );

$op = array();
foreach ( $items as $item ) {
Expand Down Expand Up @@ -184,6 +185,30 @@ public function increase_throughput( $records_per_page ) {
return PHP_INT_MAX;
}

private function add_export_ip_column( array $columns ): array {
if ( 'no-collect-ip' === AAL_Main::instance()->settings->get_option( 'log_visitor_ip_source' ) ) {
return $columns;
}

$ip_label = __( 'IP', 'aryo-activity-log' );

$result = array();
$inserted = false;
foreach ( $columns as $key => $label ) {
$result[ $key ] = $label;
if ( 'source' === $key ) {
$result['ip'] = $ip_label;
$inserted = true;
}
}

if ( ! $inserted ) {
$result['ip'] = $ip_label;
}

return $result;
}

private static function format_source_label( $raw ) {
$parsed = AAL_API::parse_request_source( $raw );
$parts = array();
Expand Down
3 changes: 3 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ You can report security bugs through the Patchstack Vulnerability Disclosure Pro

== Changelog ==

= 2.13.1 - 2026-08-26 =
* Fix: CSV export file missing IP column ([Topic](https://wordpress.org/support/topic/missing-source-ip-in-csv-export/))

= 2.13.0 - 2026-08-24 =
* Removed: Email notifications feature (hidden since 2.5 for sites that never enabled it) has been fully removed

Expand Down
143 changes: 143 additions & 0 deletions tests/phpunit/test-export.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

class AAL_Test_Export extends WP_UnitTestCase {

private function get_export_instance(): AAL_Export {
return new AAL_Export();
}

private function invoke_add_export_ip_column( AAL_Export $export, array $columns ): array {
$method = new ReflectionMethod( AAL_Export::class, 'add_export_ip_column' );
$method->setAccessible( true );

return $method->invoke( $export, $columns );
}

private function invoke_prep_row( AAL_Export $export, $item, array $columns ): array {
$method = new ReflectionMethod( AAL_Export::class, 'prep_row' );
$method->setAccessible( true );

$list_table = $this->getMockBuilder( AAL_Activity_Log_List_Table::class )
->disableOriginalConstructor()
->onlyMethods( [ 'get_action_label' ] )
->getMock();

$list_table->method( 'get_action_label' )
->willReturnArgument( 0 );

return $method->invoke( $export, $item, $columns, $list_table );
}

private function set_ip_source_option( string $value ): void {
update_option( 'activity-log-settings', [ 'log_visitor_ip_source' => $value ] );

$settings = AAL_Main::instance()->settings;
$ref = new ReflectionProperty( $settings, 'options' );
$ref->setAccessible( true );
$ref->setValue( $settings, null );
}

public function test_ip_column_inserted_after_source() {
$this->set_ip_source_option( 'REMOTE_ADDR' );
$export = $this->get_export_instance();

$columns = [
'date' => 'Date',
'author' => 'User',
'source' => 'Source',
'type' => 'Topic',
];

$result = $this->invoke_add_export_ip_column( $export, $columns );

$keys = array_keys( $result );
$this->assertSame( [ 'date', 'author', 'source', 'ip', 'type' ], $keys );
$this->assertSame( 'IP', $result['ip'] );
}

public function test_ip_column_omitted_when_no_collect() {
$this->set_ip_source_option( 'no-collect-ip' );
$export = $this->get_export_instance();

$columns = [
'date' => 'Date',
'author' => 'User',
'source' => 'Source',
'type' => 'Topic',
];

$result = $this->invoke_add_export_ip_column( $export, $columns );

$this->assertArrayNotHasKey( 'ip', $result );
$this->assertSame( [ 'date', 'author', 'source', 'type' ], array_keys( $result ) );
}

public function test_ip_column_appended_when_source_column_missing() {
$this->set_ip_source_option( 'REMOTE_ADDR' );
$export = $this->get_export_instance();

$columns = [
'date' => 'Date',
'author' => 'User',
'type' => 'Topic',
];

$result = $this->invoke_add_export_ip_column( $export, $columns );

$keys = array_keys( $result );
$this->assertSame( [ 'date', 'author', 'type', 'ip' ], $keys );
$this->assertSame( 'IP', $result['ip'] );
}

public function test_prep_row_populates_source_and_ip() {
$this->set_ip_source_option( 'REMOTE_ADDR' );
$export = $this->get_export_instance();

$columns = [
'source' => 'Source',
'ip' => 'IP',
];

$item = (object) [
'hist_ip' => '10.0.0.1',
'request_source' => 'rest',
'hist_time' => time(),
'user_id' => 0,
'object_type' => 'Posts',
'object_subtype' => 'post',
'object_name' => 'hello',
'action' => 'updated',
];

$row = $this->invoke_prep_row( $export, $item, $columns );

$this->assertSame( '10.0.0.1', $row['ip'] );
$this->assertNotEmpty( $row['source'] );
}

public function test_prep_row_ip_empty_source_when_no_request_source() {
$this->set_ip_source_option( 'REMOTE_ADDR' );
$export = $this->get_export_instance();

$columns = [
'source' => 'Source',
'ip' => 'IP',
];

$item = (object) [
'hist_ip' => '192.168.1.1',
'request_source' => '',
'hist_time' => time(),
'user_id' => 0,
'object_type' => 'Posts',
'object_subtype' => 'post',
'object_name' => 'test',
'action' => 'created',
];

$row = $this->invoke_prep_row( $export, $item, $columns );

$this->assertSame( '192.168.1.1', $row['ip'] );
$this->assertSame( '', $row['source'] );
}
}
Loading