Skip to content

Commit

Permalink
Merge pull request #99 from 10up/fix/external-content
Browse files Browse the repository at this point in the history
[External content] Fixes, better docs, more filters, and unit tests
  • Loading branch information
felipeelia committed Feb 29, 2024
2 parents c369841 + a0250c7 commit bc5e41d
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 38 deletions.
85 changes: 69 additions & 16 deletions includes/classes/Feature/ExternalContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public function __construct() {

$this->title = esc_html__( 'External Content', 'elasticpress-labs' );

$this->summary = __(
'List meta keys containing a path or a URL, and ElasticPress will index the content of those path or URL. For example, for a meta key called <code>meta_key</code> with <code>https://wordpress.org/news/wp-json/wp/v2/posts/16837</code> as its value, the JSON returned by that REST API endpoint will be indexed in a meta key called <code>ep_external_content_meta_key</code>.',
'elasticpress-labs'
);

parent::__construct();
}

Expand All @@ -44,7 +49,7 @@ public function __construct() {
* @return void
*/
public function setup() {
add_filter( 'ep_prepare_meta_data', [ $this, 'append_external_content' ] );
add_filter( 'ep_prepare_meta_data', [ $this, 'append_external_content' ], 10, 2 );
add_filter( 'ep_prepare_meta_allowed_protected_keys', [ $this, 'allow_meta_keys' ], 10, 2 );

/**
Expand All @@ -71,10 +76,23 @@ public function requirements_status() {
* Set the `settings_schema` attribute
*/
public function set_settings_schema() {
$weighting_dashboard_url = ( ! defined( 'EP_IS_NETWORK' ) || ! EP_IS_NETWORK ) ?
admin_url( 'admin.php?page=elasticpress-weighting' ) :
admin_url( 'admin.php?page=elasticpress' );

$help_text = sprintf(
/* translators: Search Fields & Weighting Dashboard URL */
__(
'Add one field per line. Visit the <a href="%s">Search Fields & Weighting Dashboard</a> if you want to make their <code>ep_external_content_*</code> version searchable.',
'elasticpress-labs'
),
$weighting_dashboard_url
);

$this->settings_schema = [
[
'default' => '',
'help' => '<p>' . __( 'Add one field per line', 'elasticpress-labs' ) . '</p>',
'help' => '<p>' . $help_text . '</p>',
'key' => 'meta_fields',
'label' => __( 'Meta fields with external URLs', 'elasticpress-labs' ),
'type' => 'textarea',
Expand All @@ -85,15 +103,21 @@ public function set_settings_schema() {
/**
* Append external content to the document meta data
*
* @param array $post_meta Document's meta data
* @param array $post_meta Document's meta data
* @param \WP_Post|null $post Post object
* @return array
*/
public function append_external_content( $post_meta ) {
public function append_external_content( $post_meta, $post = null ) {
global $wp_filesystem;

require_once ABSPATH . '/wp-admin/includes/file.php';
WP_Filesystem();

$post_indexable = \ElasticPress\Indexables::factory()->get( 'post' );
$test_meta_value = method_exists( $post_indexable, 'get_test_meta_value' ) ?
$post_indexable->get_test_meta_value() :
'test-value';

$meta_keys = $this->get_meta_keys();
foreach ( $meta_keys as $meta_key ) {
if ( ! isset( $post_meta[ $meta_key ] ) ) {
Expand All @@ -103,6 +127,23 @@ public function append_external_content( $post_meta ) {
$meta_value = (array) $post_meta[ $meta_key ];
$meta_value = reset( $meta_value );

$should_skip = empty( $meta_value ) || $test_meta_value === $meta_value;

/**
* Filter if the meta value should be skipped
*
* @since 2.3.0
* @hook ep_external_content_should_skip
* @param {bool} $should_skip Whether the meta value should be skipped
* @param {mixed} $meta_value Meta value being analyzed
* @param {string} $meta_key Meta key being analyzed
* @param {WP_Post|null} $post Current post object
* @return {bool} Whether the meta value should be skipped
*/
if ( apply_filters( 'ep_external_content_should_skip', $should_skip, $meta_value, $meta_key, $post ) ) {
continue;
}

/**
* The field value can either be a simple string or a JSON array with a list of URLs.
*/
Expand Down Expand Up @@ -134,6 +175,10 @@ public function append_external_content( $post_meta ) {
*/
$request_url = apply_filters( 'ep_external_content_remote_request_url', $external_path_and_url );

if ( ! filter_var( $request_url, FILTER_VALIDATE_URL ) ) {
continue;
}

/**
* Filter the arguments of the remote request
*
Expand All @@ -149,7 +194,8 @@ public function append_external_content( $post_meta ) {
$post_meta,
$meta_key,
wp_remote_retrieve_body( $remote_get ),
$external_path_and_url
$external_path_and_url,
$remote_get
);
}

Expand Down Expand Up @@ -218,8 +264,13 @@ public function get_stored_meta_key( $meta_key ) {
* @return array
*/
public function allow_meta_keys( $meta_keys ) {
$external_meta_keys = $this->get_meta_keys();
if ( empty( $external_meta_keys ) ) {
return $meta_keys;
}

$stored_meta_keys = array_reduce(
$this->get_meta_keys(),
$external_meta_keys,
function ( $acc, $meta_key ) {
$acc[] = $this->get_stored_meta_key( $meta_key );
return $acc;
Expand Down Expand Up @@ -304,25 +355,27 @@ public function maybe_parse_js( $content, $path_or_url ) {
/**
* Add the content of external sources to the post meta array
*
* @param array $post_meta Array of all post meta
* @param string $meta_key Meta key
* @param string $content Contents of the external source
* @param string $path_or_url Path or URL of the external source
* @param array $post_meta Array of all post meta
* @param string $meta_key Meta key
* @param string $content Contents of the external source
* @param string $path_or_url Path or URL of the external source
* @param string $additional_data Additional data. Contains the HTTP response if the content was fetched remotely
* @return array
*/
protected function add_external_content_to_post_meta( $post_meta, $meta_key, $content, $path_or_url ) {
protected function add_external_content_to_post_meta( $post_meta, $meta_key, $content, $path_or_url, $additional_data = [] ) {
/**
* Filter the content.
*
* @since 2.3.0
* @hook ep_external_content_file_content
* @param {string} $content Content being processed
* @param {string} $path_or_url Path or URL
* @param {string} $meta_key The meta key that contains the path or URL
* @param {array} $post_meta Post meta
* @param {string} $content Content being processed
* @param {string} $path_or_url Path or URL
* @param {string} $meta_key The meta key that contains the path or URL
* @param {array} $post_meta Post meta
* @param {array} $additional_data Additional data. Contains the HTTP response if the content was fetched remotely
* @return {string} New $content
*/
$content = apply_filters( 'ep_external_content_file_content', $content, $path_or_url, $meta_key, $post_meta );
$content = apply_filters( 'ep_external_content_file_content', $content, $path_or_url, $meta_key, $post_meta, $additional_data );

if ( empty( $content ) ) {
return $post_meta;
Expand Down
80 changes: 58 additions & 22 deletions tests/phpunit/feature/TestExternalContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class TestExternalContent extends \WP_UnitTestCase {
* Setup each test
*/
public function set_up() {
parent::set_up();

$instance = new ExternalContent();
Features::factory()->register_feature( $instance );
Features::factory()->activate_feature( 'external_content' );
Expand All @@ -36,14 +38,6 @@ public function set_up() {
add_filter( 'pre_http_request', [ $this, 'force_http_response' ] );
}

/**
* Clean up after each test
*/
public function tear_down() {
remove_filter( 'pre_option_ep_feature_settings', [ $this, 'set_settings' ] );
remove_filter( 'pre_http_request', [ $this, 'force_http_response' ] );
}

/**
* Get External Content feature
*
Expand Down Expand Up @@ -86,7 +80,7 @@ public function test_set_settings_schema() {

$expected_schema = [
'default' => '',
'help' => '<p>Add one field per line</p>',
'help' => '<p>Add one field per line. Visit the <a href="http://example.org/wp-admin/admin.php?page=elasticpress-weighting">Search Fields & Weighting Dashboard</a> if you want to make their <code>ep_external_content_*</code> version searchable.</p>',
'key' => 'meta_fields',
'label' => 'Meta fields with external URLs',
'type' => 'textarea',
Expand All @@ -111,11 +105,12 @@ public function test_append_external_content() {

$this->assertSame( $post_meta['ep_external_content_meta_key_1'], ' {"id":123,"content":"Lorem ipsum"}' );

$change_via_filter = function ( $content ) {
$change_via_filter = function ( $content, $path_or_url, $meta_key, $post_meta, $additional_data ) {
$this->assertSame( $content, '{"id":123,"content":"Lorem ipsum"}' );
$this->assertSame( $additional_data['code'], 123 );
return 'Something different';
};
add_filter( 'ep_external_content_file_content', $change_via_filter );
add_filter( 'ep_external_content_file_content', $change_via_filter, 10, 5 );

$post_meta = $this->get_feature()->append_external_content( $original_post_meta );
$this->assertSame( $post_meta['ep_external_content_meta_key_1'], ' Something different' );
Expand Down Expand Up @@ -173,10 +168,49 @@ public function test_append_external_content_remote_request_filters() {
];

$this->get_feature()->append_external_content( $original_post_meta );
}

remove_filter( 'ep_external_content_remote_request_url', $change_url );
remove_filter( 'ep_external_content_remote_request_args', $change_args );
remove_filter( 'pre_http_request', $check );
/**
* Test the ep_external_content_should_skip filter
*
* @group external-content
*/
public function test_ep_external_content_should_skip() {
$original_post_meta = [
'meta_key_1' => 'https://example.org/news/wp-json/wp/v2/posts/1',
];
$this->get_feature()->append_external_content( $original_post_meta );

$this->assertSame( 1, did_action( 'ep_external_content_item_processed' ) );

$skip_meta_value = function ( $should_skip, $meta_value, $meta_key, $post ) {
$this->assertFalse( $should_skip );
$this->assertSame( $meta_value, 'https://example.org/news/wp-json/wp/v2/posts/1' );
$this->assertSame( $meta_key, 'meta_key_1' );
$this->assertNull( $post );
return true;
};
add_filter( 'ep_external_content_should_skip', $skip_meta_value, 10, 4 );
$this->get_feature()->append_external_content( $original_post_meta );

$this->assertSame( 1, did_action( 'ep_external_content_item_processed' ) );
}

/**
* Test the append_external_content method with an invalid URL
*
* @group external-content
*/
public function test_append_external_content_invalid_url() {
$original_post_meta = [
'meta_key_1' => '/news/wp-json/wp/v2/posts/1',
];
$this->get_feature()->append_external_content( $original_post_meta );

$this->assertSame( 1, did_filter( 'ep_external_content_remote_request_url' ) );

// It will not even try to filter the args, as a request will not be sent.
$this->assertSame( 0, did_filter( 'ep_external_content_remote_request_args' ) );
}

/**
Expand All @@ -196,8 +230,6 @@ public function test_get_meta_keys() {
add_filter( 'ep_external_content_meta_keys', $change_via_filter );

$this->assertSame( $this->get_feature()->get_meta_keys(), array_merge( $expected, [ 'meta_key_3' ] ) );

remove_filter( 'ep_external_content_meta_keys', $change_via_filter );
}

/**
Expand All @@ -216,8 +248,6 @@ public function test_get_stored_meta_key() {
add_filter( 'ep_external_content_stored_meta_key', $change_via_filter, 10, 2 );

$this->assertSame( $this->get_feature()->get_stored_meta_key( 'meta_key' ), 'ep_external_content_meta_keychanged' );

remove_filter( 'ep_external_content_stored_meta_key', $change_via_filter );
}

/**
Expand All @@ -231,8 +261,13 @@ public function test_allow_meta_keys() {
'ep_external_content_meta_key_1',
'ep_external_content_meta_key_2',
];

$this->assertSame( $this->get_feature()->allow_meta_keys( [ 'some_other_key' ] ), $expected );

$expected = [
'ep_external_content_meta_key_1',
'ep_external_content_meta_key_2',
];
$this->assertSame( $this->get_feature()->allow_meta_keys( [] ), $expected );
}

/**
Expand Down Expand Up @@ -288,8 +323,6 @@ public function test_maybe_limit_size_filter_max_size() {
$post_meta = $this->get_feature()->append_external_content( $original_post_meta );

$this->assertStringNotContainsString( ' (trimmed)', $post_meta['ep_external_content_meta_key_1'] );

remove_filter( 'ep_external_content_max_size', $change_size );
}

/**
Expand Down Expand Up @@ -352,7 +385,10 @@ public function set_settings() {
* @return array
*/
public function force_http_response() {
return [ 'body' => $this->html_return ];
return [
'code' => 123,
'body' => $this->html_return,
];
}

/**
Expand Down

0 comments on commit bc5e41d

Please sign in to comment.