Wordpress plugin update - php

I need to implement update for my plugin which is not on wordpress repository.
What I need to know is difference between two filters:
'site_transient_update_plugins' and 'pre_set_site_transient_update_plugins'
I implemented one class for update with 'pre_set_site_transient_update_plugins' filter:
class WPAutoUpdate{
public $current_version;
public $update_path;
public $plugin_slug;
public $slug;
function __construct($current_version, $update_path, $plugin_slug){
$this->current_version = $current_version;
$this->update_path = $update_path;
$this->plugin_slug = $plugin_slug;
list ($t1, $t2) = explode('/', $plugin_slug);
$this->slug = str_replace('.php', '', $t2);
add_filter('pre_set_site_transient_update_plugins', array(&$this, 'check_update'));
}
public function check_update($transient){
if (empty($transient->checked)) {
return $transient;
}
$remote_version = $this->getRemote_version();
if (version_compare($this->current_version, $remote_version, '<')) {
$obj = new stdClass();
$obj->slug = $this->slug;
$obj->new_version = $remote_version;
$obj->url = $this->update_path;
$obj->package = $this->update_path;
$transient->response[$this->plugin_slug] = $obj;
}
return $transient;
}
public function getRemote_version(){
$request = wp_remote_post($this->update_path, array('body' => array('action' => 'version')));
if (!is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200) {
return $request['body'];
}
return false;
}
}
An instance of this class will be created from the main file of plugin:
$pluginData = get_plugin_data(__FILE__);
$plugin_current_version = $pluginData['Version'];
$plugin_remote_path = 'https://mysite.com/myplugin';
$plugin_slug = plugin_basename(__FILE__);
new WPAutoUpdate ($plugin_current_version, $plugin_remote_path, $plugin_slug);
The only problem is when I use 'pre_set_site_transient_update_plugins' filter and when new version of plugin is available, when I visit plugin page for the first time there is no information about new version. And then when I refresh the page there will be update option and each next visit on plugin page there will be update option, just not for the first visit.
And when I use 'site_transient_update_plugins' filter update information will be shown for the first visit and all works fine. Just I am worried because filter 'pre_set_site_transient_update_plugins' will be called just twice and 'site_transient_update_plugins' will be called 11 times.
So if I use 'site_transient_update_plugins' all will works fine but my function on this hook, which contain wp_remote_post() function, will be called 11 times on each visit plugin page.
Is that smart to do, is that to much expensive operation. Does anyone has some advice.

Related

Joomla 3.x Override button functions in custom component

I'm trying to override the buttons in my joomla component.
I've managed fine with the save function by adding code into the controller.
public function save($key = null, $urlVar = null)
{
$uri = JUri::getInstance();
$requestData = JRequest::getVar('jform', array(), 'post', 'array');
$user =& JFactory::getUser();
$userId = $user->get( 'id' );
$idToUse = $requestData['id'];
I want to do the same thing with save and close and save and new but I can't figure out how to do it. I thought that I needed to go to the view.html and look at the custom functions:
JToolBarHelper::title(JText::_('COM_SHOPPER_TITLE_SELECTOR'), 'selector.png');
// If not checked out, can save the item.
if (!$checkedOut && ($canDo->get('core.edit') || ($canDo->get('core.create'))))
{
JToolBarHelper::apply('selector.apply', 'JTOOLBAR_APPLY');
JToolBarHelper::save('selector.save', 'JTOOLBAR_SAVE');
}
if (!$checkedOut && ($canDo->get('core.create')))
{
JToolBarHelper::custom('selector.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false);
}
So I thought I just needed to add a function save2new() but I can't figure out how to make it work.
Any thoughts on where I'm going wrong would be great.
I guess you are looking for registerTask.
If you want to call save method for save2new task than you need to call registerTask inside constructor __constructor
$this->registerTask('save2new', 'save');
https://docs.joomla.org/API17:JController::registerTask

wordpress shortcode caching

I've developed an plugin where i make use of shortcodes. One of these shortcodes retrieves external information through communicate with an API.
The function that's called by the shortcode, communicates several times with the API. How could i cache all separate calls.
Let me try to explain it with some code
Example code
public function generateData($atts, $content = null, $tag = null){
// $this->API is a extended class to retrieve the API data
// example one calling the api
$data1 = $this->API->getData(array(
'teamlevel' => 'beginner'
));
$data2 = $this->API->getData(array(
'competition' => 'baseball'
));
}
add_shortcode('getdata', 'generateData');
class API {
public function getData($params){
// communicate with the api en return the data
}
}
Above code is working but without caching. Now i've tried to make use of wordpress get_transient and set_transient on the following way
public function generateData($atts, $content = null, $tag = null){
// $this->API is a extended class to retrieve the API data
// example one calling the api
// new chaining method cache
// every data call could be cached, i thought this could be based on shortcode name ($tag)
// set the shortcode name
$this->API->cacheShortcodeName = $tag; // getdata
$data1 = $this->API->cache()->getData(array(
'teamlevel' => 'beginner'
));
$data2 = $this->API->cache()->getData(array(
'competition' => 'baseball'
));
}
add_shortcode('getdata', 'generateData');
class API {
private $cacheDuration;
protected $cacheShortcodeName;
public function getData($params){
// before communication with the api check if there is cache with hasCache
// 1. $this->hasCache
// if result is true return cached data
// 2. return cached data
// else communicatie with the API en set new cache data
// 3. retrieve data from api en set new cached data
}
// default cache duration (1 day) in seconds
public function cache($cacheDuration = 86400){
$this->cacheDuration = $cacheDuration;
return $this;
}
public function hasCache(){
// check if there is cache
$cache = get_transient(md5($this->cacheShortcodeName));
if(!empty($cache)){
return true;
}
return false;
}
public function setCache($data){
set_transient(md5($this->cacheShortcodeName), $data, $this->cacheDuration);
}
public function getCache(){
$cache = get_transient(md5($this->cacheShortcodeName));
return $cache;
}
}
But the problem is when the cache is saved within the function setCache each time the shortcode name is set, and therefore i think its overriding itself. How could i store every call separately?

I'm trying to save data in memcached from a php script so that my website can directly use the data

The script works fine and is setting the data, but the website code is unable to use it and is instead setting its own memcached values. My website code is written in codeIgniter framework. I don't know why this is happening.
My script code :-
function getFromMemcached($string) {
$memcached_library = new Memcached();
$memcached_library->addServer('localhost', 11211);
$result = $memcached_library->get(md5($string));
return $result;
}
function setInMemcached($string,$result,$TTL = 1800) {
$memcached_library = new Memcached();
$memcached_library->addServer('localhost', 11211);
$memcached_library->set(md5($string),$result, $TTL);
}
/*---------- Function stores complete product page as one function call cache -----------------*/
function getCachedCompleteProduct($productId,$brand)
{
$result = array();
$result = getFromMemcached($productId." product page");
if(true==empty($result))
{
//------- REST CODE storing data in $result------
setInMemcached($productId." product page",$result,1800);
}
return $result;
}
Website Code :-
private function getFromMemcached($string) {
$result = $this->memcached_library->get(md5($string));
return $result;
}
private function setInMemcached($string,$result,$TTL = 1800) {
$this->memcached_library->add(md5($string),$result, $TTL);
}
/*---------- Function stores complete product page as one function call cache -----------------*/
public function getCachedCompleteProduct($productId,$brand)
{
$result = array();
$result = $this->getFromMemcached($productId." product page");
if(true==empty($result))
{
// ----------- Rest Code storing data in $result
$this->setInMemcached($productId." product page",$result,1800);
}
return $result;
}
This is saving data in memcached. I checked by printing inside the if condition and checking the final result
Based on the CodeIgniter docs, you can make use of:
class YourController extends CI_Controller() {
function __construct() {
$this->load->driver('cache');
}
private function getFromMemcached($key) {
$result = $this->cache->memcached->get(md5($key));
return $result;
}
private function setInMemcached($key, $value, $TTL = 1800) {
$this->cache->memcached->save(md5($key), $value, $TTL);
}
public function getCachedCompleteProduct($productId,$brand) {
$result = array();
$result = $this->getFromMemcached($productId." product page");
if( empty($result) ) {
// ----------- Rest Code storing data in $result
$this->setInMemcached($productId." product page",$result,1800);
}
return $result;
}
}
Personally try to avoid 3rd party libraries if it already exists in the core framework. And I have tested this, it's working superbly, so that should fix this for you :)
Just remember to follow the instructions at http://ellislab.com/codeigniter/user-guide/libraries/caching.html#memcached to set the config as needed for the memcache server

what is the purpose of having function exec() in Hook.php in prestashop

In the Header.tpl file there is a hook {$HOOK_TOP} which contains all the header part including menu, search etc... You can check that in this URL
In the FrontController it shows... 'HOOK_TOP' => Hook::exec('displayTop'),
it means in the Hook page there is a function called exec(). But I cannot understand the code properly in the exec() call.
It tells it Execute modules for specified hook. When I searched for "displayTop" I got a module name called blocktopmenu.php.
Execution only goes through 2 functions:
public function hookDisplayTop($param)
{
$this->user_groups = ($this->context->customer->isLogged() ? $this->context->customer->getGroups() : array(Configuration::get('PS_UNIDENTIFIED_GROUP')));
$this->page_name = Dispatcher::getInstance()->getController();
if (!$this->isCached('blocktopmenu.tpl', $this->getCacheId()))
{
$this->makeMenu();
$this->smarty->assign('MENU_SEARCH', Configuration::get('MOD_BLOCKTOPMENU_SEARCH'));
$this->smarty->assign('MENU', $this->_menu);
$this->smarty->assign('this_path', $this->_path);
}
$this->context->controller->addJS($this->_path.'js/hoverIntent.js');
$this->context->controller->addJS($this->_path.'js/superfish-modified.js');
$this->context->controller->addCSS($this->_path.'css/superfish-modified.css');
$html = $this->display(__FILE__, 'blocktopmenu.tpl', $this->getCacheId());
//print_r($html);//exit;
return $html;
}
and
protected function getCacheId($name = null)
{//echo"asdasdsad";exit;
parent::getCacheId($name);
$page_name = in_array($this->page_name, array('category', 'supplier', 'manufacturer', 'cms', 'product')) ? $this->page_name : 'index';
return 'blocktopmenu|'.(int)Tools::usingSecureMode().'|'.$page_name.'|'.(int)$this->context->shop->id.'|'.implode(', ',$this->user_groups).'|'.(int)$this->context->language->id.'|'.(int)Tools::getValue('id_category').'|'.(int)Tools::getValue('id_manufacturer').'|'.(int)Tools::getValue('id_supplier').'|'.(int)Tools::getValue('id_cms').'|'.(int)Tools::getValue('id_product');
}
But this public function hookDisplayTop($param) never gets called in the whole folder anywhere. I searched it but never found it in any file.
The exec() function shows below
public static function exec($hook_name, $hook_args = array(), $id_module = null, $array_return = false, $check_exceptions = true)
{
// Check arguments validity
if (($id_module && !is_numeric($id_module)) || !Validate::isHookName($hook_name))
throw new PrestaShopException('Invalid id_module or hook_name');
// If no modules associated to hook_name or recompatible hook name, we stop the function
if (!$module_list = Hook::getHookModuleExecList($hook_name))
return '';
// Check if hook exists
if (!$id_hook = Hook::getIdByName($hook_name))
return false;
// Store list of executed hooks on this page
Hook::$executed_hooks[$id_hook] = $hook_name;
// print_r(Hook::$executed_hooks);exit;
$live_edit = false;
$context = Context::getContext();
if (!isset($hook_args['cookie']) || !$hook_args['cookie'])
$hook_args['cookie'] = $context->cookie;
if (!isset($hook_args['cart']) || !$hook_args['cart'])
$hook_args['cart'] = $context->cart;
$retro_hook_name = Hook::getRetroHookName($hook_name);
//print_r($hook_name);exit;
// Look on modules list
$altern = 0;
$output = '';
foreach ($module_list as $array)
{
// Check errors
if ($id_module && $id_module != $array['id_module'])
continue;
if (!($moduleInstance = Module::getInstanceByName($array['module'])))
continue;
// Check permissions
if ($check_exceptions)
{
$exceptions = $moduleInstance->getExceptions($array['id_hook']);
$controller = Dispatcher::getInstance()->getController();
if (in_array($controller, $exceptions))
continue;
//retro compat of controller names
$matching_name = array(
'authentication' => 'auth',
'compare' => 'products-comparison',
);
if (isset($matching_name[$controller]) && in_array($matching_name[$controller], $exceptions))
continue;
if (Validate::isLoadedObject($context->employee) && !$moduleInstance->getPermission('view', $context->employee))
continue;
}
// Check which / if method is callable
$hook_callable = is_callable(array($moduleInstance, 'hook'.$hook_name));
$hook_retro_callable = is_callable(array($moduleInstance, 'hook'.$retro_hook_name));
if (($hook_callable || $hook_retro_callable) && Module::preCall($moduleInstance->name))
{
$hook_args['altern'] = ++$altern;
// Call hook method
if ($hook_callable)
$display = $moduleInstance->{'hook'.$hook_name}($hook_args);
else if ($hook_retro_callable)
$display = $moduleInstance->{'hook'.$retro_hook_name}($hook_args);
// Live edit
if (!$array_return && $array['live_edit'] && Tools::isSubmit('live_edit') && Tools::getValue('ad') && Tools::getValue('liveToken') == Tools::getAdminToken('AdminModulesPositions'.(int)Tab::getIdFromClassName('AdminModulesPositions').(int)Tools::getValue('id_employee')))
{
$live_edit = true;
$output .= self::wrapLiveEdit($display, $moduleInstance, $array['id_hook']);
}
else if ($array_return)
$output[] = $display;
else
$output .= $display;
}
}
if ($array_return)
return $output;
else
return ($live_edit ? '<script type="text/javascript">hooks_list.push(\''.$hook_name.'\'); </script>
<div id="'.$hook_name.'" class="dndHook" style="min-height:50px">' : '').$output.($live_edit ? '</div>' : '');// Return html string
}
I am not going to explain you the code line by line here, but i will explain you what the exec static member do.
When ever you call
Hook::exec("HookName");
It performs the following processes for you.
1) First it checks whether the hook is available or not? If it is not available return false;
2) Second it gets the module list for that hook from database. Also narrow down the list by exceptions for the modules for the hooks for the current page.
3) After it gets all the module(s) for the hook called for the current loaded (or called page) page, it calls the hooks function in the module. If you check modules for a specific hook you will find public function for that hook. Lets consider the Top hook. In modules you will have public functions like
public function hookTop // or public function hookDisplayTop for compatibility reasons
Please not that PS performs some other operations also there.
The above details are just giving you the idea that how hooks and modules work in PS.
Also taking the above theory, i implemented the same operations in Codeigniter and Zend Framework for my own projects, and it works like a charm ;) .
If you still have any other questions, let me know and i will provide you as much details as i can.
Thank you
Lines who call the HookDiplayTop are :
// Call hook method
if ($hook_callable)
$display = $moduleInstance->{'hook'.$hook_name}($hook_args);
else if ($hook_retro_callable)
$display = $moduleInstance->{'hook'.$retro_hook_name}($hook_args);

php passing object of an object: reference or value?

Hi all I'm using zend framework (but I think this is irrelevant) and php5 and I just want to modify an object of an object
public function saveSite($post) {
$form = new Diff_Form_Download();
$subform = new Diff_Form_DownloadSubform();
$form = $this->view->form;
$newSite = 0;
$sitesRecord = new Diff_Model_Sites();
$debugString = null;
if (is_array($post)) {
$subform = $this->getSubformByPost($post);
$debugString = $subform->getContent();
echo $debugString;
//new site instertion
if (is_null($subform)) {
$subform = $form->getSubForm('NewSite');
$newSite = 1;
}
$values = reset($subform->getValues());
$sitesRecord = Doctrine_Core::getTable('Diff_Model_Sites')->findOneBy('idSite', $values['idSite']);
if ($sitesRecord) {
$sitesRecord->idSite = $values['idSite']; //useless but necessary to make Doctrine understand to use update?
} else { //if the record is not present instantiate a new object (otherwise save() will not work
$sitesRecord = new Diff_Model_Sites();
}
$sitesRecord->content = $subform->getContent(); //$values['content'];
$sitesRecord->newHtml = $subform->getContent();
$sitesRecord->url = $values['url'];
$sitesRecord->shortName = $values['shortName'];
$sitesRecord->lastChanged = date("Y-m-d H:i:s");
$sitesRecord->pollingHours = $values['pollingHours'];
$sitesRecord->minLengthChange = $values['minLenghtChange'];
if (Zend_Auth::getInstance()->hasIdentity()) { //save the owner
$sitesRecord->idOwner = Zend_Auth::getInstance()->getIdentity()->idOwner; //retrieve the owner
$sitesRecord->save();
} else {
throw new Exception("your session have expired: \n please login again");
}
}
}
/**
* return the calling subform
* #param type $post
* #return type
*/
public function getSubformByPost($post) {
$form = new Diff_Form_Download();
$form = $this->view->form;
$subform = new Diff_Form_DownloadSubform();
$subformName = "site" . $post['idSite'];
$subform = $form->getSubForm($subformName);
return $subform;
}
public function refreshOneDiff($post) {
$debugString;
if (is_array($post)) {
$form = new Diff_Form_Download();
$form = $this->view->form;
$subform = new Diff_Form_DownloadSubform();
$subform = $this->getSubformByPost($post);
if (!$subform)
$subform = $this->view->form->getSubformByPost('NewSite');
$url = $subform->getUrl();
$idSite = $subform->getIdSite();
$crawler = new Crawler();
$newpageContent = $crawler->get_web_page($url);
$siteRecord = new Diff_Model_Sites();
$siteRecord = $subform->getSiteRecord();
if ($siteRecord) //check if the record is not null
$oldpageContent = $siteRecord->get('content');
else
$oldpageContent = null;
$differences = $this->getDiff($oldpageContent, $newpageContent);
if (!is_null($differences)) {
$siteRecord->content = $newpageContent;
$subform->setContent($newpageContent);
$subform->setContentDiff($differences);
$subform->setSiteRecord($siteRecord);
$subform = $this->getSubformByPost($post);
$debugString = $subform->getContent();
}
//echo $debugString;
$sitePresence = Doctrine_Core::getTable('Diff_Model_Sites')->findOneBy('idSite', $idSite);
if ($sitePresence) {
//$this->saveSite($post);
$this->debugtry($post);
}
} else {
}
}
Basically what I'm doing here is:
1) grab a the form from the view
2) grab a subform from the form (let's call it SubformX)
3) grab an object "siteRecordX" from SubformX
4) change a value of "siteRecordX"
5) call a function saveRecord()
6) In this function regrab the same SubformX and echoing the value of the object siteRecordX
Surprisingly if i change a variable of SubformX it will stay that way, if I change a variable of an object of SubformX it will remain unchanged (if I retrieve SubformX).
It looks like, even if SubformX is passed by reference it is not the same for it's subobjects, wich are passed by value and so they disappear changing the context of the function.
Can you please help me?
Thanks
EDIT
I still cannot solve this issue nor understand it:
This is the constructor of the subform:
public function __construct($site = null, $options = null) {
if ($site instanceof Diff_Model_Sites) {
$this->_shortName = $site->get('shortName');
$this->_url = $site->get('url');
$this->_content = $site->get('content');
$this->_idSite = $site->get('idSite');
$this->_siteRecord = $site;
$this->_lastChanged = $site->get('lastChanged');
}parent::__construct($options);}
while this is the function of SubformX i use to set the value.
public function setContent($contentText) {
$this->_siteRecord->content = $contentText;
$this->_content = $contentText;
}
and this is the function of the subform that I call to get the value
public function getContent() {
if (isset($this->_siteRecord)) {
//return $this->_content;
return $this->_siteRecord->content;
}
}
with the commented line I'm able to retrieve the updated value, not with the second.
This is a real mystery to me because i set and get them exactly the same way at exactly the same point and i cannot understand the difference.
Your _siteRecord property is an ORM object (Doctrine, it appears). So its data may have some behaviors that are not standard for a reference-type object. It surely has some override of __get and __set. It also employs caching. These things are necessary to keep the database-model interaction working properly, but they can confuse what should be a reference and value types. (See: http://www.codinghorror.com/blog/2006/06/object-relational-mapping-is-the-vietnam-of-computer-science.html)
P.S.: in your constructor you use:
$this->_content = $site->get('content');
$this->_siteRecord = $site;
but in your getContent() you use:
$this->_siteRecord->content;
That difference might be part of the problem.
Thank you all guys. It was Doctrine caching.
I have not investigated further the problem, but after getting rid of Doctrine everything works fine.
I have lost one entire day after this issue.
Moreover today I have lost another day for another curious problem related to Doctrine.
It seems that each time you gather data from your db Doctrine decode them for you (just like the php function utf8_decode($data).
Of course if you get the data and then put it back in the db again it will result in a total mayhem of coding and decoding.
This is enough. I still think that ORM are great programming tools but simply Doctrine is not.
I will not rest in peace since I'll have it eliminated from my program.
I will use Zend_Db library instead. Which I have mostly already done without regret and without facing the above-mentioned Doctrine's problems.
Again thanks to Seth Battin and Dave Random for the help and patience to understand my noob-coding.

Categories