0

I want to show adsense ads below the 4th and 20th paragraph of every blog post, ONLY if there is a 20th paragraph.

I managed to insert an ad below the 4th ad by placing the following code in my functions.php file, however I don't know how to add an additional ad after the 20th.

// Insert ads after second paragraph of single post content.

add_filter( 'the_content', 'prefix_insert_post_ads' );

function prefix_insert_post_ads( $content ) {

    $ad_code = '<div style="float:left;padding: 15px;">
                      <script type="text/javascript">
                         google_ad_client = "ca-pub-xxxxxxxxxxxx";
                         google_ad_slot = "xxxxxxxxxx";
                         google_ad_width = 300;
                         google_ad_height = 250;
                      </script>

                      <!-- Ad Name -->
                      <script type="text/javascript"
                         src="//pagead2.googlesyndication.com/pagead/show_ads.js">
                      </script>
                   </div>';

    if ( is_single() && ! is_admin() ) {
        return prefix_insert_after_paragraph( $ad_code, 3, $content );
    }

    return $content;
}

// Parent Function that makes the magic happen

function prefix_insert_after_paragraph( $insertion, $paragraph_id, $content ) {
    $closing_p = '</p>';

    $paragraphs = explode( $closing_p, $content );

    foreach ( $paragraphs as $index => $paragraph ) {

        if ( trim( $paragraph ) ) {
            $paragraphs[ $index ] .= $closing_p;
        }

        if ( $paragraph_id == $index + 1 ) {
            $paragraphs[ $index ] .= $insertion;
        }
    }

    return implode( '', $paragraphs );
}
0

2 Answers 2

0

Have faith ;-)

Unfortunately, your code ain't correct in multiple ways. It assumes that the content only consists of content enclosed by paragraphs and doesn't work correctly if not.

This would be one solution:

add_filter('the_content', 'prefix_insert_post_ads');


/**
 * Content Filter 
 */
function prefix_insert_post_ads($content) {

    $insertion = 'Your AD Code';

    if (is_single() && ! is_admin()) {
        return prefix_insert_after_paragraphs($content, $insertion, array(4,20));
    }

    return $content;

}

// Function that makes the magic happen correctly

function prefix_insert_after_paragraphs($content, $insertion, $paragraph_indexes) {

    // find all paragraph ending offsets

    preg_match_all('#</p>#i', $content, $matches, PREG_SET_ORDER+PREG_OFFSET_CAPTURE);

    // reduce matches to offset positions

    $matches = array_map(function($match) {
        return $match[0][1] + 4; // return string offset + length of </p> Tag
    }, $matches);

    // reverse sort indexes: plain text insertion just works nicely in reverse order

    rsort($paragraph_indexes); 

    // cycle through and insert on demand

    foreach ($paragraph_indexes as $paragraph_index) {
        if ($paragraph_index <= count($matches)) {
            $offset_position = $matches[$paragraph_index-1];
            $content = substr($content, 0, $offset_position) . $insertion . substr($content, $offset_position);
        }
    }

    return $content;

}

Best regards from Salzburg!

0

To properly count paragraphs, and to be consistant, the best will be is to make use of raw post content, and then apply the wpautop filter to the raw content. This way, WordPress will handle all the variables which at the end will determine how paragraphs are build and displayed

We can also look at a couple of other things to make this as reliable as possible

  • Because this is only needed for a single post, we will make use of the queried object to get our raw post content from

  • Make sure we have a minimum amount of paragraphs before inserting our adds

  • Make use of the in_the_loop() condition to only target the main query loop

  • -

I have decided to add all of this in a class

/** 
 * Class AdsINParagraphs
 * 
 * Class to inject ads into single post's content between paragraphs 
 * as required
 */
class GoogleAdsINParagraphs
{
     /** 
     * @var string $ad
     * @access protected
     * @since 1.1.0
     */
    protected $ad;

     /** 
     * @var int|string $min
     * @access protected
     * @since 1.1.0
     */
    protected $min;

     /** 
     * @var array $inject
     * @access protected
     * @since 1.1.0
     */
    protected $inject;

     /** 
     * @var $post = NULL
     * @access protected
     * @since 1.1.0
     */
    protected $post = NULL;

     /** 
     * @var $paragraphs = NULL
     * @access protected
     * @since 1.1.0
     */
    protected $paragraphs = NULL;

     /** 
     * @var $paraCount = 0
     * @access protected
     * @since 1.1.0
     */
    protected $paraCount = 0;

     /** 
     * @var $contentReplacement = NULL
     * @access protected
     * @since 1.1.0
     */
    protected $contentReplacement = NULL;

    /**
     * Public method __construct()
     *
     * Constructor for the GoogleAdsINParagraphs class
     *
     * @param string     $ad     The add that should be injected
     * @param string|int $min    The minimum amount of paragraphs that must exist
     * @param array      $inject An array of paragraph numbers where the add should be injected
     *                           If you need an ad before the content, simply pass 0 as first value
     * @access public
     * @since 1.1.0
     */
    public function __construct( $ad = NULL, $min = 4, $inject = [] )
    {
        $this->ad     = $ad;
        $this->min    = $min;
        $this->inject = $inject;
    }

    /**
     * Public method init()
     *
     * Initialize the 'the_content' filter callback
     *
     * @access public
     * @since 1.1.0
     */
    public function init()
    {
        add_filter( 'the_content', [$this, 'postContent'] );
    }

    /**
     * Protected method initHelperMethods()
     *
     * Initialize all the helper functions for the 'the_content' filter callback
     *
     * @access protected
     * @since 1.1.0
     */
    protected function initHelperMethods()
    {
        $this->post();
        $this->paragraphs();
        $this->paraCount();
        $this->contentReplacement();
    }


    /**
     * Protected method post()
     *
     * Gets the current post object and sanitize the post object. Sanitation 
     * is done as precaution should the query object being altered by some other
     * program/function/malicious code
     *
     * @access protected
     * @since 1.1.0
     */
    protected function post()
    {
        $post_raw   = get_queried_object();
        // Sanitize the post object in case that something externally changed the queried object
        $post       = sanitize_post( $post_raw );
        $this->post = $post;
    }

    /**
     * Protected method paragraphs()
     *
     * Gets the current post's post content, sanitizes it and then applies the wpautop filter
     * function to it to apply p tags to the raw content. After the filter function is applied,
     * the content is exploded into an array of paragraphs
     *
     * @access protected
     * @since 1.1.0
     */
    protected function paragraphs()
    {
        // Just in case, as extra precaution, run the raw post comment through wp_kses_post 
        $noEvilContent    = wp_kses_post( $this->post->post_content );
        $peedContent      = wpautop( $noEvilContent );
        $paragraphs       = explode( '<p>', $peedContent );

        $this->paragraphs = $paragraphs;
    }

    /**
     * Protected method paraCount()
     *
     * Counts the amount of paragraphs created by the paragraphs() method
     *
     * @access protected
     * @since 1.1.0
     */
    protected function paraCount()
    {
        $paraCount       = count( $this->paragraphs );

        $this->paraCount = (int) $paraCount;
    }

    /**
     * Protected method contentReplacement()
     *
     * This is where everything happens. The following checks are run
     * before ads are inserted into the content
     * - Check if there is at least the set minimum amount of paragraphs. 
     *   Checks are done against $this->min
     * - Check if there at least enough paragraphs to fullfil the lowest
     *   passed number in $this->inject
     * - Check to see if $this->inject is a valid array with values
     *
     * If all checks pass, ads is inserted into the content. If any value
     * in $this->inject is more than the amount of paragraphs, the ad is ignored
     * and not inserted
     *
     * @access protected
     * @since 1.1.0
     */
    protected function contentReplacement()
    {
        // Lets first run all our checks 

        $this->contentReplacement = $contentReplacement = NULL;

        // Make sure that we have at least more paragraphs than our minimum, bail if not
        if ( $this->paraCount < $this->min ) 
            return $this->contentReplacement;

        // Make sure that $this->inject is an array and not empty
        if (    !is_array( $this->inject ) 
             || !$this->inject
        )
            return $this->contentReplacement;

        /**
         * We will do the following checks and validation on $this->inject
         * - validate the array of ID's and remove negative numbers
         * - sort $this->inject array numerically ASC according to passed ID's 
         * - remove possible dublicates
         */
        $this->inject = filter_var( 
            $this->inject, 
            FILTER_VALIDATE_INT, 
            [
                'flags' => FILTER_REQUIRE_ARRAY,
                'options' => [
                    'min_range' => 0
                ]
            ]
        ); 
        asort( $this->inject );
        $this->inject = array_unique( $this->inject );

        // Make sure that we actaully have enough paragraphs to inject an add into 

        if ( $this->paraCount < $this->inject[0] )
            return $this->contentReplacement;

        // Now we can start to inject our ads into our content. Set $output as empty string
        $output = '';
        foreach ( $this->paragraphs as $key=>$paragraph ) {
            // Add ad in front of content if $this->inject[0] === 0
            if (    0 === $key 
                 && 0 === $this->inject[0]
            ) {
                $output .= '<p>' . $this->ad . '</p>' . $paragraph;
            } elseif ( !in_array( $key, $this->inject ) ) {
                $output .= $paragraph; 
            } else {
                $output .= $paragraph . '<p>' . $this->ad . '</p>';
            }
        } // endforeach

        $this->contentReplacement = $output;
    }

   /**
     * Public method postContent()
     *
     * This is the callback method for the 'the_content' filter. The content passed by reference
     * inside the filter is replaced by any valid value from $this->contentReplacement. This is done
     * purely for convenience
     *
     * @access public
     * @since 1.1.0
     * @return $content
     */
    public function postContent( $content )
    {
        // Lets first run our checks, make sure this is a single page and the main query
        if ( !is_single() )
            return $content;

        if ( !in_the_loop() )
            return $content;

        // Initialize our other helper methods. They should only run inside our condition
        $this->initHelperMethods();

        // Make sure $this->contentReplacement is not NULL, if so, just return $content
        if ( NULL === $this->contentReplacement )
            return $content;

        // We can now replace $content with $this->contentReplacement
        $content = $this->contentReplacement;

        return $content;
    }
} // end of class GoogleAdsINParagraphs

You can now use it as follow

$ad      = 'PLACE YOUR AD HERE';
$add_ads = new GoogleAdsINParagraphs( 
    $ad,     // Your ad which you want to add
    4,       // There should be at least 4 paragraphs
    [4, 20]  // Array of paragraph numbers after which you want to inject an add
);
$add_ads->init();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.