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

Excellent suggestions, Marcus.

pic001.webp

Post.php

PHP:
<?php

class Andy_ChangeDate_ControllerPublic_Post extends XFCP_Andy_ChangeDate_ControllerPublic_Post
{
   public function actionChangedate()
   {
     // if you are not a super admin, return
     if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return;
     }
         
     // get post_id from route
     $postId = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
     
     // get all post data
     $post = $this->getModelFromCache('XenForo_Model_Post')->getPostById($postId);
     
     $viewParams = array('post' => $post);
     
     // display andy_changedate template overlay
     return $this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
   }
   
   public function actionChangedatesave()
   {
     // make sure data comes from $_POST
     $this->_assertPostOnly();
     
     // if you are not a super admin, you will get an error
     if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return;
     }
     
     $post['post_id'] = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
     
     // get new post date from input text      
     $newPostDate = $this->_input->filterSingle('new_post_date', XenForo_Input::STRING);
     
     // convert to unix timestamp
     $dateline = strtotime($newPostDate ) - XenForo_Locale::getTimeZoneOffset();     
     
     if (!$dateline)
     {
       return $this->responseError(new XenForo_Phrase('incorrect_date_format_entered'));
     }
     
     //########################################
     // start database operations
     //########################################
     
     // update the xf_post.post_date
     $dw = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post');
     $dw->setExistingData($post['post_id']);
     $dw->set('post_date', $dateline);
     $dw->save();
     
     // update the xf_post.position for each post in the thread
     // also updates other tables with first post and last post information
     $threadId = $dw->get('thread_id');
     $dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
     $dw->setExistingData($threadId);
     $dw->rebuildDiscussion();
     $dw->save();
     
     //########################################
     // return with response redirect
     //########################################
         
     return $this->responseRedirect(
     XenForo_ControllerResponse_Redirect::SUCCESS,
     XenForo_Link::buildPublicLink('posts', $post),'Post Date Changed');       
   }
}

?>
 
I would include the post creation time in the dialog with $post['formatted_date'] = date('d/m/y g:i a', $post['post_date']);:

PHP:
  public function actionChangedate()
{
// if you are not a super admin, return
if (!XenForo_Visitor::getInstance()->isSuperAdmin())
{
return;
}
// get post_id from route
$postId = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
// get all post data
$post = $this->getModelFromCache('XenForo_Model_Post')->getPostById($postId);
$post['formatted_date'] = date('d/m/y g:ia', $post['post_date']);
$viewParams = array('post' => $post);
// display andy_changedate template overlayreturn
$this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
}
... with <input type=.... value="{$post.formated_date}" />
 
Post.php

PHP:
<?php

class Andy_ChangeDate_ControllerPublic_Post extends XFCP_Andy_ChangeDate_ControllerPublic_Post
{
   public function actionChangedate()
   {
     // if you are not a super admin, return
     if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return;
     }
         
     // get post_id from route
     $postId = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
     
     // get all post data
     $post = $this->getModelFromCache('XenForo_Model_Post')->getPostById($postId);
     
     // created formatted date for template
     $post['formatted_date'] = date('m/d/y g:ia', $post['post_date'] + XenForo_Locale::getTimeZoneOffset());
     
     $viewParams = array('post' => $post);
     
     // display andy_changedate template
     return $this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
   }
   
   public function actionChangedatesave()
   {
     // make sure data comes from $_POST
     $this->_assertPostOnly();
     
     // if you are not a super admin, you will get an error
     if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return;
     }
     
     $post['post_id'] = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
     
     // get new post date from input text      
     $newPostDate = $this->_input->filterSingle('new_post_date', XenForo_Input::STRING);
     
     // convert to unix timestamp
     $dateline = strtotime($newPostDate ) - XenForo_Locale::getTimeZoneOffset();     
     
     if (!$dateline)
     {
       return $this->responseError(new XenForo_Phrase('incorrect_date_format_entered'));
     }
     
     //########################################
     // start database operations
     //########################################
     
     // update the xf_post.post_date
     $dw = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post');
     $dw->setExistingData($post['post_id']);
     $dw->set('post_date', $dateline);
     $dw->save();
     
     // update the xf_post.position for each post in the thread
     // also updates other tables with first post and last post information
     $threadId = $dw->get('thread_id');
     $dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
     $dw->setExistingData($threadId);
     $dw->rebuildDiscussion();
     $dw->save();
     
     //########################################
     // return with response redirect
     //########################################
         
     return $this->responseRedirect(
     XenForo_ControllerResponse_Redirect::SUCCESS,
     XenForo_Link::buildPublicLink('posts', $post),'Post Date Changed');       
   }
}

?>
 
This addon is perfect.

You can also use the admin's display time preferences. Each XenForo language can have a specific way to display time different, like 12/20/13 3:00pm or 20.12.2013 15:00. The time format is accessible in library/XenForo/Locale.php

You would just have to change these two lines and replace PHP functions date() and strototime() with the XenForo ones:
PHP:
$post['formatted_date'] = date('m/d/y g:ia', $post['post_date'] + XenForo_Locale::getTimeZoneOffset());
and
PHP:
$dateline = strtotime($newPostDate ) - XenForo_Locale::getTimeZoneOffset();

But I do not know how these XenForo_Locale functions work.
 
Maybe $post['formatted_date'] = XenForo_Locale::dateTime($post['post_date']);

I have not found a function in XenForo_Locale that returns a UNIX Timestamp.
 
I just checked to see what would happen if I use 13:00 instead of 1:00pm and it makes no difference, both work fine. So it appears only the date format needs to be addressed.
 
This is with the PHP function date():
You could look at the XenForo_Visitor object to get the user's language and their date display format?

PHP:
$visitor = XenForo_Visitor::getInstance();
$language = $visitor->getLanguage();

$closeDate = date($language['date_format'], $poll.close_date);
could be rewritten as


PHP:
$language = XenForo_Visitor::getInstance()->getLanguage();
date = date($language['date_format'], $post['post_date');
 
You could use that, which only uses the date and time format from XenForo_Visitor with the PHP functions:

PHP:
// accesses database table xf_language
$userLanguage = XenForo_Visitor::getInstance()->getLanguage();

// accesses database fields date_format and time_format
$timeFormat = $userLanguage['date_format'] . ' ' . $userLanguage['time_format'];

$post['formatted_date'] = date($timeFormat, $post['post_date'] + XenForo_Locale::getTimeZoneOffset());

It's better to just use a XenForo function instead of the PHP function date() as it would be easier to access the data. But this code here should work.
 
Last edited:
In your first function you add the local time zone, in the second function you substract it. Maybe it's right to do so, I just noticed it.
 
PHP:
 public function actionChangedate()
{
// if you are not a super admin, return
if (!XenForo_Visitor::getInstance()->isSuperAdmin())
{
return;
}
// get post_id from route
$postId = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
// get all post data
$post = $this->getModelFromCache('XenForo_Model_Post')->getPostById($postId);
// created formatted date for template
$userLanguage = XenForo_Visitor::getInstance()->getLanguage();
$timeFormat = $userLanguage['date_format'] . ' ' . $userLanguage['time_format'];
$post['formatted_date'] = date($timeFormat, $post['post_date'] + XenForo_Locale::getTimeZoneOffset());
$viewParams = array('post' => $post);
// display andy_changedate template
return $this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
}
 
Hi Marcus,

I added the code and it works great!

pic001.webp

When I change my date or time settings, the template displays accordingly.

Admin CP -> Appearance -> Language -> English
 
Last edited:
Post.php

PHP:
<?php

class Andy_ChangeDate_ControllerPublic_Post extends XFCP_Andy_ChangeDate_ControllerPublic_Post
{
   public function actionChangedate()
   {
     // if you are not a super admin, return
     if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return;
     }
         
     // get post_id from route
     $postId = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
     
     // get all post data
     $post = $this->getModelFromCache('XenForo_Model_Post')->getPostById($postId);
     
     // format date and time for use in template     
     $userLanguage = XenForo_Visitor::getInstance()->getLanguage();
     $timeFormat = $userLanguage['date_format'] . ' ' . $userLanguage['time_format'];
     $post['formatted_date'] = date($timeFormat, $post['post_date'] + XenForo_Locale::getTimeZoneOffset());
     
     $viewParams = array('post' => $post);
     
     // display andy_changedate template
     return $this->responseView('Andy_DateChange_ViewPublic_Post','andy_changedate',$viewParams);
   }
   
   public function actionChangedatesave()
   {
     // make sure data comes from $_POST
     $this->_assertPostOnly();
     
     // if you are not a super admin, you will get an error
     if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       return;
     }
     
     $post['post_id'] = $this->_input->filterSingle('post_id', XenForo_Input::UINT);
     
     // get new post date from input text      
     $newPostDate = $this->_input->filterSingle('new_post_date', XenForo_Input::STRING);
     
     // convert to unix timestamp
     $dateline = strtotime($newPostDate ) - XenForo_Locale::getTimeZoneOffset();     
     
     if (!$dateline)
     {
       return $this->responseError(new XenForo_Phrase('incorrect_date_format_entered'));
     }
     
     //########################################
     // start database operations
     //########################################
     
     // update the xf_post.post_date
     $dw = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post');
     $dw->setExistingData($post['post_id']);
     $dw->set('post_date', $dateline);
     $dw->save();
     
     // update the xf_post.position for each post in the thread
     // also updates other tables with first post and last post information
     $threadId = $dw->get('thread_id');
     $dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
     $dw->setExistingData($threadId);
     $dw->rebuildDiscussion();
     $dw->save();
     
     //########################################
     // return with response redirect
     //########################################
         
     return $this->responseRedirect(
     XenForo_ControllerResponse_Redirect::SUCCESS,
     XenForo_Link::buildPublicLink('posts', $post),'Post Date Changed');       
   }
}

?>
 
As an explanation, $userLanguage = XenForo_Visitor::getInstance():

In this file: library/XenForo/Visitor.php the function getInstance() is executed.
You could also do XenForo_Visitor::getUserId() to execute the function getUserId() there.

Or XenForo_Locale::getTimeZoneOffset() is executing the function getTimeZoneOffset() from library/XenForo/Locale.php
 
Your programming skills and knowledge of Xenforo code is amazing, Marcus.

Thank you so much for teaching me how to get started making my own add-ons. I think this one is finished for now.
 
Back
Top Bottom