Jonathan Stegall
Jonathan Stegall

Reputation: 530

PHP insert ad after X paragraphs, then every Y paragraphs if the text is long enough

I need to insert an ad code at intervals in this way:

  1. $insert_every_paragraphs is a variable that indicates how often a paragraph should appear in the text. 10, for example.
  2. $minimum_paragraph_count is used to see if the text is long enough for any ads, and also the very first ad should appear after this many paragraphs (then it should repeat the intervals in #1). 4, for example.
  3. The ad codes work like this: x100, x101, x102, x103, etc. Users can set how many are eligible to be added. They render like [cms_ad:x100] and PHP replaces them later (that part works fine).
  4. The code should stop adding ads once it gets to the end of #3. That is, even if it has enough paragraphs to keep adding ads, it should stop if it has reached x104 (in this example).

So in this example, it would work like this: after 4 paragraphs, insert x100. Then, every 10 paragraphs, insert another until x103 has been inserted. Don't insert x104, even if there are 100 paragraphs. But also, if there aren't at least 34 paragraphs, x103 would never appear.

What I have so far is this:

$paragraph_end = '</p>';

$insert_every_paragraphs = 10;
$minimum_paragraph_count = 4;

$embed_prefix      = 'x';
$start_embed_id    = 'x100';
$start_embed_count = intval( str_replace( $embed_prefix, '', $start_embed_id ) ); // ex 100
$end_embed_id      = 'x103';
$end_embed_count   = intval( str_replace( $embed_prefix, '', $end_embed_id ) ); // ex 104

$paragraph_positions = array();
$last_position       = -1;

while ( stripos( $content, $paragraph_end, $last_position + 1 ) !== false ) {
    // Get the position of the end of the next $paragraph_end.
    $last_position         = stripos( $content, $paragraph_end, $last_position + 1 ) + 3;
    $paragraph_positions[] = $last_position;
}

// If the total number of paragraphs is bigger than the minimum number of paragraphs
if ( count( $paragraph_positions ) >= $minimum_paragraph_count ) {
    // How many ads have been added?
    $n = $start_embed_count;
    // Store the position of the last insertion.
    $previous_position = $start_embed_count;
    $i                 = 0;
    while ( $i < count( $paragraph_positions ) && $n <= $end_embed_count ) {

        if ( 0 === ( $i + 1 ) % $insert_every_paragraphs && isset( $paragraph_positions[ $i ] ) ) {
            $shortcode = "\n" . '[cms_ad:' . $embed_prefix . (int) $n . ']' . "\n";

            $position = $paragraph_positions[ $i ] + 1;

            if ( $position > $previous_position ) {
                $content = substr_replace( $content, $shortcode, $paragraph_positions[ $i ] + 1, 0 );
                // Increase the saved last position.
                $previous_position = $position;
                // Increment number of shortcodes added to the post.
                $n++;
            }
            // Increase the position of later shortcodes by the length of the current shortcode.
            foreach ( $paragraph_positions as $j => $pp ) {
                if ( $j > $i ) {
                    $paragraph_positions[ $j ] = $pp + strlen( $shortcode );
                }
            }
        }
        $i++;
    }
}

I thought this was working okay when the numbers were 4 and 6 instead of 4 and 10, but the error became clear when I started adjusting the values. It currently inserts an ad every 10 paragraphs, and of course it does not insert an ad after the fourth paragraph.

I'm not opposed to using explode or other methods for this, of course, but this was what got me the farthest.

Upvotes: 1

Views: 1641

Answers (1)

Manuel Otto
Manuel Otto

Reputation: 6540

Why not split the paragraphs into an array, add the ads, then join it together again. It will remove most of the string-concatination headache.

Please note i did not implement the formatting of the shortcode.

$insert_every_paragraphs = 2;
$minimum_paragraph_count = 1;
$adcodes = ['x100', 'x101', 'x102', 'x103'];

$paragraphs = [];
$split = explode('</p>',$content);
foreach($split as $paragraph){
  //filter out empty paragraphs
  if(strlen($paragraph)>3)
      $paragraphs[] = $paragraph . '</p>';
}

$paragraph_count = count($paragraphs);
$ad_num = 0;

$counter = $minimum_paragraph_count;
for($i=0;$i<$paragraph_count;$i++){
    if($counter==0){
        $adcode = $adcodes[$ad_num];
        $shortcode = "[cms_ad:$adcode]";

        array_splice($paragraphs,$i+$ad_num,0,$shortcode);
        $counter = $insert_every_paragraphs;
        $ad_num++;

        if($ad_num>=count($adcodes))
            break;
    }
    $counter--;
}


$content = implode('',$paragraphs);

Upvotes: 3

Related Questions