Change position word key [ad] in my old posts

Topics: ASP.NET 2.0, Business Logic Layer, Controls, Themes
Apr 13, 2015 at 10:48 AM
Hi,
Google don't like banner adv in above the fold of Post.
I have this situation in every posts this word key [ad] to the beginning of each post.

It's possibile to put it after the second paragraph, as a reference point at the end of the period? And change all my old posts?

For example
Now:
[ad]
dfadfadfadfadf

After:
kjdfadjfdafda.
dfadfadfad.
[ad]
dfadfadfadf.

Can you help me?
Thanks
Fabry
Apr 13, 2015 at 1:49 PM
Edited Apr 13, 2015 at 2:02 PM
How is the placeholder "[ad]" inserted?
Is it auto inserted or manually written to the start and end of each post?
If it's auto inserted then just remove the extension/code responsible for that.
If it's actually part of the post content then you could write a simple script to cycle through your posts to remove the placeholders.
i.e.
for each post in post list
find "[ad]" in body and replace with empty string
save post

Then use something like the following to insert ads in new positions.
using System;
using System.Text.RegularExpressions;
using System.Web;
using BlogEngine.Core;
using BlogEngine.Core.Web.Controls;
using BlogEngine.Core.Web.Extensions;

/// <summary> 
/// Bare bones code to insert content after second paragraph in post body and at body end.
/// </summary> 
[Extension("Inserts content after second paragraph and end of post body", "1.0", "Fabry")]
public class AdInserter
{   
    public AdInserter()
    {
        Post.Serving += InsertContent;
    }   
    
    private static void InsertContent(object sender, ServingEventArgs e)
    {
        if (e.Location == ServingLocation.SinglePost)
        {
            Match para = Regex.Match(e.Body, @"<p[^>]*>\s*.+?\s*</p>");

            int paraCount = 1;
            int pos = 0;

            while (para.Success && paraCount < 3)
            {
                pos = para.Index + para.Value.Length;
                para = para.NextMatch();
                paraCount++;
            }

            e.Body = e.Body.Insert(pos, "Your ad stuff") + "Your ad stuff";
        }       
    }
}
Note that this is bare minimum code that assumes multiple paragraphs, you might want to expand this to include conditions.
Apr 13, 2015 at 8:59 PM
Hi Andy,
great.. happy to see you again..

Only two things
1) if I wanted to avoid putting the advertisement next to the image of the post? how can I do a check and understand that there is an image in that row and then skip to the next sentence?

For example:
1)Not GOOD SITUATION
[ad]
image or

image
[ad]

2)GOOD SITUATION
dfadfafadf
[ad]
dfadfdfa
image

or
dfadfadf
image
adfadfa
[ad]


2) how do I run this code? What are the steps? example: Installing VS2014 .. download source BlogEngine version ... then?

Thank you very much for your help Andy..
Apr 13, 2015 at 9:01 PM
Placeholder "[ad]" is auto inserted.. For new post i can to change position. Problem is only for old posts
Thanks
Apr 14, 2015 at 11:31 AM
Hi Fabry,

So you are auto inserting "[ad]" at start and end of post content and this gets saved with the post?
Then at runtime "[ad]" gets replaced with the actual advertisement.
What do you see when you open a post for editing, do you see...

[ad]
text
text
[ad]

or possibly
<p>[ad]</p>
Some posts may have first and some the other.

If that is the case then following script will remove all placeholders.

Save following as adremove.aspx page in blog root.
On first run use "<p>[ad]</p>" replacement and then do a second run with "[ad]" replacement.
<%@ Page Language="C#" %>
<%@ Import Namespace="BlogEngine.Core" %>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {        
        var posts = Post.Posts;
        for (int i = 0; i < posts.Count; i++)
        {
            Post p = posts[i];            
            p.Content = p.Content.Replace("<p>[ad]</p>", string.Empty); // first run - comment out for second run
            //p.Content = p.Content.Replace("[ad]", string.Empty); // uncomment and use me on second run
            p.Save();
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Height="100px" 
            Text="Remove ads" Width="166px" onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>
If using this script, you would then need to insert ads at runtime at specific positions rather than as placeholder substitution.
However, this starts to get complicated if you are checking for images and possibly other objects(maybe video and such like).
Also what if post is very short and only has a few paragraphs, there are many unknowns.

How about having both placeholder ads at the end of each post and then position first ad absolutely to 'appear' at the top of each post.
This is far from ideal, but much simpler.
Apr 14, 2015 at 1:09 PM
Thanks Andy,
I have 3.000 post to be changed... i will crazy.

Banner are 300x250 pixel and are positioned: one at first and one at the end of post.

Problem is only for first banner... the last isn't problem. For future isn't problem because i can put first banner manually.

For old post (only for old post) is possibile to choose number of phrase with point or words? And decide this, for example:

if the post has max 300 words i don't insert first banner because it's a short post.
if the post has more 300 words (or 400 words) i insert first banner after the third phrase (or fourth).

Perhaps to count words is the fastest solution ..

What do you think? It's possible to choose parameters for number of words and phrases with point from a txt files or input text?
Apr 14, 2015 at 3:25 PM
Edited Apr 14, 2015 at 3:49 PM
Just modify the script so that it only removes the first occurrence of "[ad]" and save it as before "adremove.aspx" in blog root.
Bring up the blogroot/adremove page and press the "remove ads" button. Run once, this takes care of the first banner.
<%@ Page Language="C#" %>
<%@ Import Namespace="BlogEngine.Core" %>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {       
        var posts = Post.Posts;
        var placeHolder = "[ad]"; //If this is what you see in post editor(assuming no tag wrapper);
        var phIndex = -1;
        
        for (int i = 0; i < posts.Count; i++)
        {
            Post p = posts[i];
            phIndex = p.Content.IndexOf(placeHolder);
            
            if (phIndex != -1)
            {
                //p.Content = p.Content.Remove(phIndex, placeHolder.Length); // Substring probably faster
                p.Content = p.Content.Substring(0, phIndex) + p.Content.Substring(phIndex + placeHolder.Length);                 

              
                p.Save();
            }
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Height="100px" 
            Text="Remove ads" Width="166px" onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>
As regards re-inserting the placeholder for the first banner back into the content, I would be inclined to count the paragraphs.
So your script might look something like the following, which you could save as say "adInsert.aspx" and run once.
<%@ Page Language="C#" %>
<%@ Import Namespace="BlogEngine.Core" %>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {       
        var posts = Post.Posts;       
        
        for (int i = 0; i < posts.Count; i++)
        {
            Post p = posts[i];
            MatchCollection matches = Regex.Matches(p.Content, @"<p[^>]*>\s*.+?\s*</p>");

            if (matches.Count > 4) // Number of paragraphs
            {
                int pos = matches[1].Index + matches[1].Value.Length; // After second paragraph
                p.Content = p.Content.Insert(pos, "[ad]");
                p.Save();
            }
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Height="100px" 
            Text="Insert ads" Width="166px" onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>
This will do the basics, if you want to check for an image then feel free to play around.
For example you could find the position of the first image and see how that fits with the position ranges of your paragraphs and decide what to do from there.

P.S. Test thoroughly offline and when happy, alter offline and upload modified posts rather than run online - might take some time with 3000 posts.
Apr 14, 2015 at 8:08 PM
Edited Apr 14, 2015 at 8:11 PM
Great Andy,

first code work perfectly, but in my editor html i have this situation
<p>[ad]</p>
<p>&nbsp;</p>
How can i delete also
<p>&nbsp;</p>
And in AdInsert i want to add [ad] with this code
<p>&nbsp;</p>
<p>[ad]</p>
<p>&nbsp;</p>
How can i change code in AdInsert..

Thanks
Fabry
Apr 14, 2015 at 9:28 PM
Ok also AdInsert Work perfectly

But Andy is possible to add in AdInsert,

1) condition: if after second paragraph contains an image jumps in third paragraph..
2) condition: if paragraph are max 6, first banner is not necessary..

So i will solve
Thankss
Apr 14, 2015 at 11:09 PM
Edited Apr 14, 2015 at 11:13 PM
Hi Fabry,

Play around with it a little, I'm sure you will suss what you need to do.

When inserting the "[ad]" it would probably be best to wrap it in a div "<div>[ad]</div>" because the tinyMCE editor will wrap it with P tags if it doesn't already have a wrapper tag. This won't happen if inserting the tags automatically, but as soon as you open the post for editing it will. So some posts will have [ad] and some <p>[ad]</p> which apart from being inconsistent is also not good markup, because when the placeholders get swapped for content you end up with
<p><div>stuff and more stuff</div></p>
Apr 19, 2015 at 7:53 PM
Hi Fabry,

Although there's plenty reasons not to do this in this way, I had some free time and decided to write the script anyway,
Script will attempt to insert banner placeholder at the end of the second paragraph or nearest paragraph to that having no images immediately preceding or after.
I still think you would be better inserting the banner placeholders at the end of your post content and using CSS to visually position the first at post start... but que sera.
<%@ Page Language="C#" %>
<%@ Import Namespace="BlogEngine.Core" %>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {       
        var posts = Post.Posts;

        for (int i = 0; i < posts.Count; i++)
        {
            Post p = posts[i];

            MatchCollection pMatches = Regex.Matches(p.Content, @"<p[^>]*>\s*.+?\s*</p>");
            int limit = pMatches.Count - 3; // Don't insert ad beyond last 3 paragraphs.

            if (limit > 2) // Insert ad somewhere after second paragraph.
            {
                // Find any image positions
                int pStart = 0;
                int pEnd;
                bool[] imgLocations = new bool[pMatches.Count];                

                for (int j = 0; j < pMatches.Count; j++)
                {
                    pEnd = pMatches[j].Index + pMatches[j].Value.Length;
                    imgLocations[j] = p.Content.Substring(pStart, pEnd - pStart).IndexOf("<img") != -1;
                    pStart = pEnd;
                }

                // Insert ad only if there is no image between paragraphs.              
                for (int j = 2; j < limit; j++)
                {
                    if (imgLocations[j - 1] == false && imgLocations[j] == false && imgLocations[j + 1] == false)
                    {
                        int pos = pMatches[j - 1].Index + pMatches[j - 1].Value.Length;
                        p.Content = p.Content.Insert(pos, "<div>[ad]</div>");
                        p.Save();
                        break;
                    }
                }               
            }
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Height="100px" 
            Text="Insert ads" Width="166px" onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>
Apr 20, 2015 at 9:35 AM
Thanks Andy,
this solution is only for old post.

I will try this evening your script and i tell you.

Your code is very important for this forum.
Fabry