1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Simple preg_replace on Post Content

Discussion in 'XenForo Development Discussions' started by AdamCapriola, May 23, 2012.

  1. AdamCapriola

    AdamCapriola Member

    I'm in the process of porting a vB add-on I created that does a simple search/replace on content within posts and conversations, excluding sigs and whatnot, just the messages themselves (I search for certain keywords to link them to reference pages). I've followed along with Kier's video, which helped explain a lot about the hooks, but I'm not sure if there is a way to further specify a hook, if I'm approaching this the wrong way, or if this is even possible.

    Right now, I'm looking at the 'message_content' hook. This is what I've tried so far:

    PHP:
    <?php
     
    class Demo_Addon
    {
        public static function 
    templateHook($hookName, &$contents, array $hookParamsXenForo_Template_Abstract $template)
        {
            if (
    $hookName 'message_content')
            {
                
    $contents .= 'This is a test.';
            }   
        }
    }
    The Code Event Listener is 'template_hook'.

    This does a marvelous job at adding 'This is a test."... but to practically every hook on the screen! It seems like a lot of templates use 'message_content', but I am trying to limit it to just posts and conversations.

    The hook I used in vB was 'postbit_display_complete', if that helps at all. I tried to deconstruct this addon since it seems similar to what I'm trying to do, but I had trouble deciphering the code. I have a long list of search/replace pairs, and I'm just trying to do copy them over as simply as possible.

    Thanks in advance for any help!
     
  2. Chris D

    Chris D XenForo Developer Staff Member

    What exactly are you trying to do? What you've done in your example above is expected.

    The message_content hook is within the message template and the message template is rendered for every single message on the screen. So the add on above is saying add This is a test. to every single message.

    But actually if you're trying to replace content within a post then hooks might not be the way to do it.

    You could extend the thread view, or even use template post render. But the appropriate method depends on exactly what you're trying to achieve.
     
  3. Jeremy P

    Jeremy P Well-Known Member

    You're probably going to want to change this
    PHP:
    if ($hookName 'message_content')
    to this..
    PHP:
    if ($hookName == 'message_content')
     
    Jake Bunce and AdamCapriola like this.
  4. AdamCapriola

    AdamCapriola Member

    Derp. Good catch! That would be the problem. I guess before I was literally targeting every hook on the page. I think everything is good now! I still need to tinker with things a little more, but that'll probably do it.

    Is there a way to limit the hook to either post OR convos, or does it always cover both?
    Here's a sample of what I was doing with vB:

    PHP:
    $search[] = '/\b(Pidgeot.{1,2}RG)\b(?![^<>]*<\/a>|[^<]*>)/';
    $replace[] = '<a href="http://pkmncards.com/card/pidgeot-firered-leafgreen-rg-10/" class="scan-link" title="Click to view this card" target="_blank">$1</a>';
     
    $search[] = '/\b(Manectric.{1,2}ex)\b(?![^<>]*<\/a>|[^<]*>)/';
    $replace[] = '<a href="http://pkmncards.com/card/manectric-ex-deoxys-dx-101/" class="scan-link" title="Click to view this card" target="_blank">$1</a>';
     
    //
    // Replace!
    //   
     
    $this->post['message'] = preg_replace$search$replace$this->post['message'], );
    I replace names of Pokemon cards within posts and link them to a database I made, so users on my Pokemon TCG forums can quickly look up the cards if they don't know what they do. The search/replace list is kind of huge and I'm going to have to monitor to see how much it slows things down, whether it's worth it or not.
     
  5. Chris D

    Chris D XenForo Developer Staff Member

    The wonderful Jake Bunce on this forum once helped me with something completely different, but I will post the code here.

    I don't think you can do this with template hooks.

    Here's what Jake helped me with. I've added your code into it that should work for making one replacement in all of the posts, but I'll leave it to you to refine it to your needs further :D

    PHP:
    <?php
     
    class YourAddOn_ThreadView extends XFCP_YourAddOn_ThreadView
    {
    public function 
    renderHtml()
    {
    parent::renderHtml();
     
    foreach (
    $this->_params['posts'] AS &$post)
    {
    $search[] = '/\b(Manectric.{1,2}ex)\b(?![^<>]*<\/a>|[^<]*>)/';
    $replace[] = '<a href="http://pkmncards.com/card/manectric-ex-deoxys-dx-101/" class="scan-link" title="Click to view this card" target="_blank">$1</a>';
     
    $post['messageHtml'] = preg_replace$search$replace,  $post['messageHtml'], );
    }
    }
    }
     
    Jake Bunce likes this.
  6. Chris D

    Chris D XenForo Developer Staff Member

    Oh your Code Event Listener, I forgot:

    PHP:
    <?php
     
    class YourAddOn_Listen
    {
    public static function 
    extend($class, array &$extend)
    {
    if (
    $class == 'XenForo_ViewPublic_Thread_View')
    {
    $extend[] = 'YourAddOn_ThreadView';
    }
    }
    }
     
  7. AdamCapriola

    AdamCapriola Member

    Thanks for the code! Jeremy P's fix seems to be working rather well and I like how simple it is, but I would like to try your solution to see if it's maybe more efficient. What is the event the Listener should look for? (Like how I'm using 'template_hook' for the original idea.) I'm not sure I totally understand how your solution "hooks" in.
     
  8. Chris D

    Chris D XenForo Developer Staff Member

    I'm a little hazy too. No doubt Jake Bunce will come up with a much better explanation later.

    But basically as far as I understand it the message template calls the $message.html variable. This method basically changes the contents of that variable for it is rendered. Whether it is more efficient or not, I don't know. But I just know it worked for me.

    The event listener should listen to load_class_view
     
    Jake Bunce likes this.

Share This Page