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

Creating the add-on Similar Threads

Discussion in 'XenForo Development Discussions' started by AndyB, Oct 14, 2013.

  1. AndyB

    AndyB Well-Known Member

    Description:

    The Similar Threads add-on will show a list of similar threads when a user is creating a new thread.

    Key Features:
    • Limit number of results (Admin Control Panel Setting)
    • Exclude common words (Admin Control Panel Setting)
    • Simple one word search
    • Node permissions honored
    • Similar Threads immediately displayed
    • Automatically disabled for displays 800px or less (Responsive design)
    • Fully phrased
    How it Works:

    When a user types a new thread title, as soon as a non-common word is entered a list of similar threads is displayed.

    Example:

    pic001.jpg
     
    LPH, CarlosMST, infis and 1 other person like this.
  2. AndyB

    AndyB Well-Known Member

    This tutorial will show the steps required to create this add-on:
    1. Create the directory structure
    2. Create the New Add-on
    3. Create the similarthreads.js file
    4. Create the Abstract.php file
    5. Create the Model.php file
    6. Create the SimilarThreads.php file
    7. Create the Route Prefix
    8. Create the Template andy_similarthreads
    9. Create the Option Group
    10. Create the Options
    11. Create the Template Modifications
    12. Create the page_container_js_head Template Modification
    13. Create the thread_create #1 Template Modification
    14. Create the thread_create #2 Template Modification
    15. Create the xenforo_data_table.css Template Modification
    16. Create the New Phrase
     
    infis likes this.
  3. AndyB

    AndyB Well-Known Member

    Create the directory structure:
    js
    --xenforo
    ----similarthreads.js
    library
    --Andy
    ----SimilarThreads
    ------ControllerPublic
    --------Abstract.php
    ------Model.php
    ------Route
    --------Prefix
    ----------SimilarThreads.php
     
    infis likes this.
  4. AndyB

    AndyB Well-Known Member

    Create the New Add-on:

    pic002.jpg
     
    infis likes this.
  5. AndyB

    AndyB Well-Known Member

    Create the similarthreads.js file:

    js/xenforo/similarthreads.js

    Code:
    !function($, window, document, _undefined)
    {
    	XenForo.similarthreadsId = function($form)
    	{		
    		var typewatch = (function()
    		{
    			var timer = 0;
    			return function(callback, ms)
    			{
    				clearTimeout (timer);
    				timer = setTimeout(callback, ms);
    			}  
    		})(); 
    		$title = $form.find('input[name="title"]');
    		$title.keyup(function() 
    		{
    			typewatch(function () 
    			{
    				XenForo.ajax(
    				$('base').attr('href') + 'similarthreads/',
    				$form.serializeArray(),
    				function(ajaxData, textStatus)
    				{
    					if (ajaxData.templateHtml)
    					{
    						new XenForo.ExtLoader(ajaxData, function()
    						{
    							$('#similarthreadsId-result').html('<div>' + ajaxData.templateHtml + '</div>');
    						});
    					}
    				});
    			}, 500);
    		});		
    	}	
    	XenForo.register('#similarthreadsId', 'XenForo.similarthreadsId');	
    }
    (jQuery, this, document);
    
     
    infis likes this.
  6. AndyB

    AndyB Well-Known Member

    Create the Abstract.php file:

    library/Andy/SimilarThreads/ControllerPublic/Abstract.php

    PHP:
    <?php

    class Andy_SimilarThreads_ControllerPublic_Abstract extends XenForo_ControllerPublic_Abstract
    {
        public function 
    actionIndex()
        {            
            
    // declare variables
            
    $searchWord '';
            
    $searchWords = array();
            
    $safeSearchWord '';       
                
            
    // get newTitle
            
    $newTitle $this->_request->getParam('title');
            
            
    // put into array
            
    $newTitle explode(' '$newTitle);
            
            
    // get options from Admin CP -> Options -> Similar Threads -> Common Words    
            
    $commonWords XenForo_Application::get('options')->commonWords;
            
            
    // convert to lowercase
            
    $commonWords strtolower($commonWords);    
            
            
    // put $commonWordsLower into an array
            
    $commonWords explode(' '$commonWords); 
            
            
    // remove any common words from array
            
    foreach($newTitle as $var)
            {
                if (!
    in_array(strtolower($var), $commonWords))
                {
                    
    $searchWords[] = $var;
                }
            }
            
            
    $count count($searchWords);
            
            
    // only continue if we have a search word
            
    if ($count 0)
            {
                
    // get first none common word
                
    $searchWord $searchWords[0];
            
                
    // make safe for database
                
    $safeSearchWord addslashes($searchWord);
            }
            
            
    // run query only if we have a search
            
    if ($safeSearchWord != '')
            {
                
    // run query in model    
                
    $threads $this->getModelFromCache('Andy_SimilarThreads_Model')->getThreads($safeSearchWord);    
            } 
            else 
            {
                
    // $viewParams needs to be an array
                
    $threads = array();                
            }
            
            
    // prepare $viewParams for template
            
    $viewParams = array(
                
    'threads' => $threads,
                
    'searchWord' => $searchWord
            
    );
            
            
    // send to template
            
    return $this->responseView('Andy_SimilarThreads_ViewPublic_SimilarThreads''andy_similarthreads'$viewParams);
        }
    }

    ?>
     
    infis likes this.
  7. AndyB

    AndyB Well-Known Member

    Create the Model.php file:

    library/Andy/SimilarThreads/Model.php

    PHP:
    <?php

    class Andy_SimilarThreads_Model extends XenForo_Model
    {
        public function 
    getThreads($safeSearchWord)
        {         
        
            
    // declare variable    
            
    $visitor XenForo_Visitor::getInstance();            
            
    $permissionCombinationId $visitor['permission_combination_id'];                            
            
            
    // get permissions
            
    $permissions $this->_getDb()->fetchAll("
                SELECT xf_permission_cache_content.cache_value, xf_permission_cache_content.content_id
                FROM xf_permission_cache_content
                INNER JOIN xf_forum ON xf_forum.node_id = xf_permission_cache_content.content_id
                WHERE xf_permission_cache_content.permission_combination_id = '
    $permissionCombinationId'
                ORDER BY xf_permission_cache_content.content_id ASC
            "
    );    
            
            foreach (
    $permissions AS $k => $v)
            {
                
    $cache_value[] = unserialize($v['cache_value']);
                
    $content_id[] = $v['content_id'];                
            }
            
            
    $i 0;
            
            foreach (
    $cache_value AS $v)
            {
                
    $view[] = $v['view'];
                
                if (
    $v['view'] != 1)
                {
                    
    $forum_id_no_permission[] = $content_id[$i];
                }
                
    $i++;
            } 
            
            
    // create whereclause for forums the user cannot view
            
    if (isset($forum_id_no_permission))
            {
                
    $whereclause 'AND xf_thread.node_id <> ' implode(' AND xf_thread.node_id <> '$forum_id_no_permission);
            }
            else
            {
                
    $whereclause '';
            } 
            
            
    // get option from Admin CP -> Options -> Similar Threads -> Maximum Results    
            
    $maxResults XenForo_Application::get('options')->maxResults;        
            
            
    // get threads
            
    return $this->_getDb()->fetchAll("
                SELECT xf_thread.thread_id, xf_thread.title, xf_node.title AS nodetitle
                FROM xf_thread
                INNER JOIN xf_node ON xf_node.node_id = xf_thread.node_id
                WHERE xf_thread.title LIKE '%
    $safeSearchWord%'
                
    $whereclause
                ORDER BY xf_thread.thread_id DESC
                LIMIT 
    $maxResults
            "
    );        
        }
    }

    ?>
     
    Last edited: Oct 15, 2013
    infis likes this.
  8. AndyB

    AndyB Well-Known Member

    Create the SimilarThreads.php file:

    library/Andy/SimilarThreads/Model/Route/Prefix/SimilarThreads.php

    PHP:
    <?php

    class Andy_SimilarThreads_Route_Prefix_SimilarThreads implements XenForo_Route_Interface
    {
        public function 
    match($routePathZend_Controller_Request_Http $requestXenForo_Router $router)
        {
            return 
    $router->getRouteMatch('Andy_SimilarThreads_ControllerPublic_Abstract''Index'$routePath);
        }
    }

    ?>
     
    infis likes this.
  9. AndyB

    AndyB Well-Known Member

    Create the Route Prefix:

    pic003.jpg
     
    infis likes this.
  10. AndyB

    AndyB Well-Known Member

    Create the Template andy_similarthreads:

    Code:
    <xen:if is="{$threads}">
    
      <div class="sectionMain similarThreads">
      
      <div class="primaryContent">
         {xen:phrase similar_threads_found_with_the_word_in_the_thread_title, 'searchWord={$searchWord}'}
      </div>
      
      <table class="dataTable">
      
      <tr class="dataRow">
      <th>{xen:phrase forum}</th>
      <th>{xen:phrase title}</th>
      </tr>
      
      <xen:foreach loop="$threads" key="$index" value="$thread">
      
      <tr class="dataRow">
      <td>{$thread.nodetitle}</td>
      <td><a href="{xen:link threads, $thread}" title="{$thread.title}" target="_blank">{$thread.title}</a></td>
      </tr>
      
      </xen:foreach>
      
      </table>
    
      </div>
    
    </xen:if>
    
    <xen:if is="!{$threads}">
    </xen:if>
    
     
    Last edited: Oct 15, 2013
    infis likes this.
  11. AndyB

    AndyB Well-Known Member

    Create the Option Group:

    This will add an option group to the Admin CP in order to allow configuring the Similar Threads add-on.

    Admin CP -> Options -> + Add Option Group

    pic004.jpg
     
    Last edited: Oct 15, 2013
    infis likes this.
  12. AndyB

    AndyB Well-Known Member

    Create the Options:

    Create the two options. Refer to the similarthreads.xml file for detailed information on each option.

    The final result will look like this:

    pic005.jpg
     
    infis likes this.
  13. AndyB

    AndyB Well-Known Member

    Create the Template Modifications:

    There are four Template Modifications that need to be created.

    The final result will look like this:

    pic006.jpg
     
    infis likes this.
  14. AndyB

    AndyB Well-Known Member

    Create the page_container_js_head Template Modification:

    Find:
    Code:
    <!--XenForo_Require:JS-->
    
    Replace:
    Code:
    $0
    <script src="js/xenforo/similarthreads.js"></script>
    
     
    infis likes this.
  15. AndyB

    AndyB Well-Known Member

    Create the thread_create #1 Template Modification:

    Find:
    Code:
    data-redirect="on"
    
    Replace:
    Code:
    $0
    id="similarthreadsId" autocomplete="off"
    
     
    infis likes this.
  16. AndyB

    AndyB Well-Known Member

    Create the thread_create #2 Template Modification:

    Find:
    Code:
    <dl class="ctrlUnit fullWidth">
    
    Replace:
    Code:
    <dl id="similarthreadsId-result"></dl>$0
    
     
    infis likes this.
  17. AndyB

    AndyB Well-Known Member

    Create the xenforo_data_table.css Template Modification:

    Find:
    Code:
    /** Data tables **/
    
    Replace:
    Code:
    $0
    .similarThreads {
        margin: 0px 30px 0px 30px;
        padding: 0px 15px 5px 15px;
    }
    
    @media (max-width:@maxResponsiveWideWidth){
        .similarthreads {
            display: none;
        }
    }
    
     
    infis likes this.
  18. AndyB

    AndyB Well-Known Member

    Create the New Phrase:

    Title
    Code:
    similar_threads_found_with_the_word_in_the_thread_title
    
    Phrase text
    Code:
    Similar threads found with the word ({searchWord}) in the thread title:
    
     
    infis likes this.
  19. AndyB

    AndyB Well-Known Member

    Moshe1010 and infis like this.
  20. MattW

    MattW Well-Known Member

    Thanks for posting this @AndyB , it's good to see the logic behind creating an add-on (y)
     

Share This Page