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
174 changes: 160 additions & 14 deletions inc/plugins/class-dynamic-content.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,26 @@ public function apply_dynamic_content( $content ) {
}

$position = strlen( $position );
$content = substr_replace( $content, $replacement, $position, strlen( $string_to_replace ) );
if ( is_array( $replacement ) ) {
$re = '/#otterDynamicLink\/?.[^"]*/';
$matches = array();
$num = preg_match_all( $re, $content, $matches, PREG_SET_ORDER, 0 );

if ( isset( $matches[0] ) ) {
$link = $this->apply_link_button( $matches[0] );
}
$_content = array_fill( 0, count( $replacement ), $content );
$content = '';
foreach ( $replacement as $key => $value ) {
$updated_content = substr_replace( $_content[ $key ], $value, $position, strlen( $string_to_replace ) );
if ( isset( $link ) && is_array( $link ) && isset( $link[ $key ] ) ) {
$updated_content = str_replace( $matches[0], $link[ $key ], $updated_content );
}
$content .= $updated_content;
}
} else {
$content = substr_replace( $content, $replacement, $position, strlen( $string_to_replace ) );
}
}

return $content;
Expand Down Expand Up @@ -132,18 +151,65 @@ public function apply_magic_tags( $data ) {
/**
* Filter post content for dynamic link.
*
* @param string $content Post content.
* @param string $content Post content.
* @param int|null $key Optional key for multiple dynamic links in the same content.
*
* @return string
*/
public function apply_dynamic_link( $content ) {
public function apply_dynamic_link( $content, $key = null ) {
if ( false === strpos( $content, '<o-dynamic-link' ) ) {
return $content;
}

$re = '/<o-dynamic-link(?:\s+(?:data-type=["\'](?P<type>[^"\'<>]+)["\']|data-target=["\'](?P<target>[^"\'<>]+)["\']|data-meta-key=["\'](?P<metaKey>[^"\'<>]+)["\']|data-context=["\'](?P<context>[^"\'<>]+)["\']|[a-zA-Z-]+=["\'][^"\'<>]+["\']))*\s*>(?<text>[^ $].*?)<\s*\/\s*o-dynamic-link>/';

return preg_replace_callback( $re, array( $this, 'apply_link' ), $content );
$matches = array();
$num = preg_match_all( $re, $content, $matches, PREG_SET_ORDER, 0 );
if ( isset( $num ) && 0 === $num ) {
return $content;
}

$resolved = array();
$clone_count = 1;
foreach ( $matches as $match ) {
$value = $this->apply_link( $match, $key );
$resolved[] = $value;
if ( is_array( $value ) ) {
$clone_count = max( $clone_count, count( $value ) );
}
}

// Replace the content for multiple dynamic links in the same content.
if ( $clone_count > 1 ) {
$output = '';
for ( $i = 0; $i < $clone_count; $i++ ) {
$clone = $content;
foreach ( $matches as $j => $match ) {
$value = $resolved[ $j ];
$replacement = is_array( $value )
? ( isset( $value[ $i ] ) ? $value[ $i ] : '' )
: $value;
$pos = strpos( $clone, $match[0] );
if ( false !== $pos ) {
$clone = substr_replace( $clone, $replacement, $pos, strlen( $match[0] ) );
}
}
$output .= $clone;
}
return $output;
}

// Replace the content for single dynamic link in the content.
$index = 0;
return preg_replace_callback(
$re,
function ( $data ) use ( &$resolved, &$index ) {
$value = isset( $resolved[ $index ] ) ? $resolved[ $index ] : $data[0];
$index++;
return is_string( $value ) ? $value : $data[0];
},
$content
);
}

/**
Expand Down Expand Up @@ -178,17 +244,62 @@ public function apply_dynamic_images( $content ) {
$rest_url = get_rest_url( null, 'otter/v1' );
$rest_url = preg_replace( '/([^A-Za-z0-9\s_-])/', '\\\\$1', $rest_url );

$re = '/' . $rest_url . '\/dynamic\/?.[^"]*/';
$re = '/' . $rest_url . '\/dynamic\/?.[^"]*/';
$matches = array();
$num = preg_match_all( $re, $content, $matches, PREG_SET_ORDER, 0 );
if ( isset( $num ) && 0 === $num ) {
return $content;
}

return preg_replace_callback( $re, array( $this, 'apply_images' ), $content );
$resolved = array();
$clone_count = 1;
foreach ( $matches as $match ) {
$value = $this->apply_images( $match );
$resolved[] = $value;
if ( is_array( $value ) ) {
$clone_count = max( $clone_count, count( $value ) );
}
}

// Replace the content for multiple dynamic images in the same content.
if ( $clone_count > 1 ) {
$output = '';
for ( $i = 0; $i < $clone_count; $i++ ) {
$clone = $content;
foreach ( $matches as $j => $match ) {
$value = $resolved[ $j ];
$replacement = is_array( $value )
? ( isset( $value[ $i ] ) ? $value[ $i ] : '' )
: $value;
$pos = strpos( $clone, $match[0] );
if ( false !== $pos ) {
$clone = substr_replace( $clone, $replacement, $pos, strlen( $match[0] ) );
}
}
$output .= $clone;
}
return $output;
}

// Replace the content for single dynamic image in the content.
$index = 0;
return preg_replace_callback(
$re,
function ( $data ) use ( &$resolved, &$index ) {
$value = isset( $resolved[ $index ] ) ? $resolved[ $index ] : $data[0];
$index++;
return is_string( $value ) ? $value : $data[0];
},
$content
);
}

/**
* Apply dynamic data.
*
* @param array $data Dynamic request.
*
* @return string|void
* @return string|string[]|void
*/
public function apply_images( $data ) {
if ( ! isset( $data[0] ) ) {
Expand Down Expand Up @@ -267,11 +378,28 @@ public function get_image( $data ) {
* @param array $data Dynamic request.
* @param bool $magic_tags Is a request for Magic Tags.
*
* @return string
* @return string|string[]
*/
public function apply_data( $data, $magic_tags = false ) {
$value = $this->get_data( $data, $magic_tags );

if ( is_array( $value ) ) {
$updated_value = array();
foreach ( $value as $key => $val ) {
$_value = $this->apply_formatting( $val, $data );

if ( isset( $data['default'] ) && false !== strpos( $data['default'], '<o-dynamic-link' ) ) {
$link = $this->apply_dynamic_link( $data['default'], $key );
if ( ! empty( $link ) ) {
$_value = preg_replace( '/(<a.*?>).*?(<\/a>)/', '$1' . $_value . '$2', $link );
}
}

$updated_value[] = $_value;
}
return $updated_value;
}
Comment on lines 383 to +401
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

This PR introduces new array-returning behavior (apply_data() can now return string[] and apply_dynamic_content() has special handling for array replacements), but there are no unit tests covering the new repeater/array paths. Since this file already has PHPUnit coverage for dynamic content, please add tests to assert correct output for array values (including multiple placeholders in the same content) to prevent regressions.

Copilot uses AI. Check for mistakes.

if ( isset( $data['before'] ) || isset( $data['after'] ) ) {
$value = $this->apply_formatting( $value, $data );
}
Expand Down Expand Up @@ -310,7 +438,7 @@ public function apply_formatting( $value, $data ) {
* @param array $data Dynamic request.
* @param bool $magic_tags Is a request for Magic Tags.
*
* @return string
* @return string|string[]
*/
public function get_data( $data, $magic_tags ) {
if ( ! ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || true === $magic_tags ) {
Expand Down Expand Up @@ -610,11 +738,12 @@ public static function query_string_to_array( $qry ) {
/**
* Apply dynamic data.
*
* @param array $data Dynamic request.
* @param array $data Dynamic request.
* @param int|null $key Optional key for multiple dynamic links in the same content.
*
* @return string
* @return string|string[]
*/
public function apply_link( $data ) {
public function apply_link( $data, $key = null ) {
$link = $this->get_link( $data );

if ( empty( $link ) ) {
Expand All @@ -627,6 +756,23 @@ public function apply_link( $data ) {
$attrs = 'target="_blank"';
}

if ( is_array( $link ) ) {
$value = array();
foreach ( $link as $link_item ) {
$value[] = sprintf(
'<a href="%s" %s>%s</a>',
esc_url( $link_item ),
$attrs,
wp_kses_post( $data['text'] )
);
}

if ( null !== $key ) {
return isset( $value[ $key ] ) ? $value[ $key ] : '';
}

return $value;
}
$value = sprintf(
'<a href="%s" %s>%s</a>',
esc_url( $link ),
Expand All @@ -642,7 +788,7 @@ public function apply_link( $data ) {
*
* @param array $data Dynamic request.
*
* @return string|void
* @return string|string[]|void
*/
public function apply_link_button( $data ) {
if ( ! isset( $data[0] ) ) {
Expand All @@ -666,7 +812,7 @@ public function apply_link_button( $data ) {
*
* @param array $data Dynamic request.
*
* @return string|void
* @return string|string[]|void
*/
public function get_link( $data ) {
if ( ! isset( $data['type'] ) ) {
Expand Down
Loading
Loading