How do I create an add-on that allows a user to click a link and call php code?

Your template could look like this.

1. You have to rename your function to actionChangedateSave. (the large "S" is the reason for the "-save" within the template: <form action="{xen:link 'posts/changedate-save', $post}")

2. You have to submit $post, so that the internal route in {xen:link} works:
PHP:
<?php
class Andy_ChangeDate_ControllerPublic_Post extends XFCP_Andy_ChangeDate_ControllerPublic_Post
{
public function actionChangedate()
{
$post['post_id'] = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
//echo 'ControllerPublic: Change Date. $postId = ' . $post['post_id'];

$viewParams = array('post' => $postId,
);

return $this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
}

public function actionChangedateSave()
..........................................................

}

This is the template andy_changedate:
PHP:
<xen:title>Date Change</xen:title>

<form action="{xen:link 'posts/changedate-save', $post}" method="post" class="xenForm AutoValidator" data-redirect="on">

   <fieldset>
   <dl class="ctrlUnit">
     <dt><label>Date:</label></dt>
     <dd><input type="text" name="title" size="30" value="{$post.date}" placeholder="Date..." class="textCtrl titleCtrl"></dd>
   </dl>
   <dl class="ctrlUnit submitUnit">
     <dt></dt>
     <dd><input type="submit" value="Change Date" class="button primary" accesskey="s" /></dd>
   </dl>
   </fieldset>

   <input type="hidden" name="_xfToken" value="{$visitor.csrf_token_page}" />
</form>

$post.date is not configured. You can get the date along with other data in the controllerPublic function, currently $post is just set for $post['post_id']. ('title' and 'message_text' are useful, so that you can see the post on that tamplate before you change the date).
 
Hi Marcus,

I've updated Post.php and the template andy_changedate. When I enter a URL like

forums/posts/1856457/changedate

I get the following error:

Undefined variable: postId

  1. XenForo_Application::handlePhpError() in Andy/ChangeDate/ControllerPublic/Post.php at line 9
  2. Andy_ChangeDate_ControllerPublic_Post->actionChangedate() in XenForo/FrontController.php at line 337
  3. XenForo_FrontController->dispatch() in XenForo/FrontController.php at line 134
  4. XenForo_FrontController->run() in /home/*/www/forums/index.php at line 13
 
  1. XenForo_Application::handlePhpError() in Andy/ChangeDate/ControllerPublic/Post.php at line 9

In that line you have a $postId which xenForo does not understand.

PHP:
$viewParams = array('post' => $postId,
);

should be

PHP:
$viewParams = array('post' => $post,
);
 
I added another isSuperAdmin check to Post.php.

library/Andy/ChangeDate/ControllerPublic/Post.php

PHP:
<?php
class Andy_ChangeDate_ControllerPublic_Post extends XFCP_Andy_ChangeDate_ControllerPublic_Post
{
   public function actionChangedate()
   {
     $post['post_id'] = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
     echo 'ControllerPublic: Change Date. $postId = ' . $post['post_id'];
     
     $viewParams = array('post' => $post,
     );
     
     if (XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return $this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
     }
   }
   
   public function actionChangedatesave()
   {
     $this->_assertPostOnly();// if you are not a super admin, you will get an error
     
     if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return;
     }
     
     $postId= $this->_input->filterSingle('post_id', XenForo_Input::UINT); //this is an integer here! I guess the easiest solution would be to use an integer value at first, before you know how you can make use of xenForos calendar for selecting a date.
     
     $newPostDate = $this->_input->filterSingle('new_post_date', XenForo_Input::UINT);
     //$dw = XenForo_DataWriter::create('XenForo_DataWriter_Post');
     //$dw->setExistingData($postId);
     //$dw->set('date', $newPostDate);
     //$dw->save();
     
     $post['post_id'] = $postId;
     
     return $this->responseRedirect(
     XenForo_ControllerResponse_Redirect::SUCCESS,
     XenForo_Link::buildPublicLink('post', $post),
     'Post Date Changed');
   }
}
 
Last edited:
In my Post.php file as shown in post #85, the last few lines are suppose to redirect back to the post, but it does not. I get the following error:

Route post/ could not be found.

Any ideas what changes I could make to redirect properly?
 
Thank you kindly, Chris. Now it redirects back to the post perfectly.

PHP:
<?php

class Andy_ChangeDate_ControllerPublic_Post extends XFCP_Andy_ChangeDate_ControllerPublic_Post
{
	public function actionChangedate()
	{
		$post['post_id'] = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
		echo 'ControllerPublic: Change Date. $postId = ' . $post['post_id'];
		
		$viewParams = array('post' => $post,
		);
		
		if (XenForo_Visitor::getInstance()->isSuperAdmin())
		{
			return $this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
		} 
	}
	
	public function actionChangedatesave()
	{
		$this->_assertPostOnly();// if you are not a super admin, you will get an error
		
		if (!XenForo_Visitor::getInstance()->isSuperAdmin())
		{
			return;
		}
		
		$postId= $this->_input->filterSingle('post_id', XenForo_Input::UINT); 
		
		// get input text from template
		$newPostDate = $this->_input->filterSingle('new_post_date', XenForo_Input::STRING);
		
		if ($newPostDate == '')
		{
			return;	
		}
		
		// get input text from template
		$newPostTime = $this->_input->filterSingle('new_post_time', XenForo_Input::STRING);
		
		// convert to unix timestamp
		$date = $newPostDate . ' ' . $newPostTime;
		$dateline = strtotime($date);
		
		//$dw = XenForo_DataWriter::create('XenForo_DataWriter_Post');
		//$dw->setExistingData($postId);
		//$dw->set('date', $newPostDate);
		//$dw->save();
		
		$post['post_id'] = $postId;
		
		$confirmation_message = 'Post Date Changed' . $dateline;
				
		return $this->responseRedirect(
		XenForo_ControllerResponse_Redirect::SUCCESS,
		XenForo_Link::buildPublicLink('posts', $post),$confirmation_message);
	} 
}
 
Last edited:
At this point I'm ready to do my first query to the database. In my stand alone scripts I would do something like:

PHP:
$sql = "
UPDATE xf_post
SET post_date='$dateline'
WHERE post_id='$postId'
LIMIT 1";

// run the SQL query
mysql_query($sql);

Can I use standard MySQL queries as shown above?
 
Another example of a query that I would like to use:

PHP:
$sql = "
SELECT thread_id
FROM xf_post
WHERE post_id='$postId'";

// execute SQL query and get result
$sql_result = mysql_query($sql,$connection);

// format results by row
while ($row = mysql_fetch_array($sql_result))
{
    $thread_id = $row["thread_id"];
}
 
I almost got it. Here's a query that almost works. The problem is $thread_id is an array, it should not be.

PHP:
		$db = XenForo_Application::getDb();
		
		$thread_qry = "
		SELECT thread_id
		FROM xf_post
		WHERE post_id='$postId'";		

		$thread_id = XenForo_Application::get('db')->fetchAll($thread_qry);
 
Here's how to run a query that will update a table:

PHP:
		$db->query("
		UPDATE xf_post
		SET post_date='$dateline'
		WHERE post_id='$postId'
		LIMIT 1");
 
When I ran my test, the time that was entered into the database was seven hours less. I suspect this has to do with the timezone, I'm in Pacific time.

I just needed to add:

date_default_timezone_set('America/Los_Angeles');
 
Last edited:
From what I understand, the proper format for a query where one or more rows will be returned is this:

PHP:
        $query = $db->fetchAll("
        SELECT post_id
        FROM xf_post
        WHERE thread_id='$thread_id'
        ORDER BY post_date ASC");
       
        foreach($query AS $rowName => $results)
        {
            $post_id[] = $results;
        }

But I'm not able to display the value of $post_id[0]. It still shows Array is instead of a post number.
 
From what I understand, the proper format for a query where one or more rows will be returned is this:

PHP:
        $query = $db->fetchAll("
        SELECT post_id
        FROM xf_post
        WHERE thread_id='$thread_id'
        ORDER BY post_date ASC");
     
        foreach($query AS $rowName => $results)
        {
            $post_id[] = $results;
        }

But I'm not able to display the value of $post_id[0]. It still shows Array is instead of a post number.
Should be
PHP:
$db->fetchAllKeyed('
SELECT post_id
        FROM xf_post
        WHERE thread_id= ?
        ORDER BY post_date ASC
', 'post_id', $threadId);
 
Hi Nobita.Kun,

Thank you for your help. Unfortunately using the code you suggested gives me this error.

The server responded with an error. The error message is in the JavaScript console.
 
Hi Nobita.Kun,

Thank you for your help. Unfortunately using the code you suggested gives me this error.
Replace $threadId = $thread_id?
Ha? I just see XenForo_Model_Post::getPostIdsInThread();
Replace that code by:
PHP:
$postModel = $this->getModelFromCache('XenForo_Model_Post');

$posts = $postModel->getPostIdsInThread($thread_id);
 
Top Bottom