I'm using woocommerce_update_product hook to get product data once a product has been created / updated.
I'm trying to get the terms from a taxonomy called wcpv_product_vendors. On first save (as draft) I can get the other product_cat terms but the terms for wcpv_product_vendors don't appear until I next save the post.
add_action( 'woocommerce_update_product', [$this, 'dcgsql_update_product'], 50, 1);
public function dcgsql_update_product(){
$get_vendors = get_the_terms($product_id, 'wcpv_product_vendors');
if (!empty($get_vendors)) {
foreach ($get_vendors as $vendor) {
$vendorsarray[] = $vendor->term_id;
}
$vendors = implode(',',$vendorsarray);
} else {
$vendors = '';
}
}
On first save as draft, $get_vendors is always empty but I have applied one.
All other terms for product_cat are coming back fine.
Use the below codes it will work...
add_action( 'woocommerce_update_product', 'dcgsql_update_product', 50, 1);
public function dcgsql_update_product(){
$get_vendors = wp_get_post_terms($product_id, 'wcpv_product_vendors');
if (!empty($get_vendors)) {
foreach ($get_vendors as $vendor) {
$vendorsarray[] = $vendor->term_id;
}
$vendors = implode(',',$vendorsarray);
} else {
$vendors = '';
}
}
I have a WordPress plugin that I want to use a cron job to check every 60 minutes an external URL (JSON) for any changes. I want to then store that response in a global variable which I can use later.
Here is my code so far...
class GetPosts
{
public $CheckPostDate;
public $SetPostData;
/**
* #param mixed $CheckPostDate
*/
public function setCheckPostDate($CheckPostDate)
{
$this->CheckPostDate = $CheckPostDate;
}
/**
* #param mixed $SetPostData
*/
public function setSetPostData($SetPostData)
{
$this->SetPostData = $SetPostData;
}
public function __construct()
{
// add custom interval
function cron_add_minute( $schedules ) {
// Adds once every minute to the existing schedules.
$schedules['everyminute'] = array(
'interval' => 60,
'display' => __( 'Once Every Minute' )
);
return $schedules;
}
add_filter( 'cron_schedules', 'cron_add_minute' );
// create a scheduled event (if it does not exist already)
function cronstarter_activation() {
if( !wp_next_scheduled( 'mycronjob' ) ) {
wp_schedule_event( time(), 'everyminute', 'mycronjob' );
}
}
// and make sure it's called whenever WordPress loads
add_action('wp', 'cronstarter_activation');
// unschedule event upon plugin deactivation
function cronstarter_deactivate() {
// find out when the last event was scheduled
$timestamp = wp_next_scheduled ('mycronjob');
// unschedule previous event if any
wp_unschedule_event ($timestamp, 'mycronjob');
}
register_deactivation_hook (__FILE__, 'cronstarter_deactivate');
function mycronjob() {
// Get the posts update JSON
$update_args = array(
'timeout' => 30
);
$check_posts_update = wp_remote_get('http://example.com', $update_args);
$checkPostDate = wp_remote_retrieve_body($check_posts_update);
if(empty($checkPostDate)) return false;
$this->setCheckPostDate($checkPostDate);
}
add_action ('mycronjob', [$this, 'my_repeat_function']);
}
}
global $GetPosts;
$GetPosts = new GetPosts();
The function checkRandom() does work every 60 seconds but it doesn't update the global variable.
since every request is separate, I'd say, save it to a file
$data = ['apples','bananas'];
file_put_contents(__DIR__.'/cron.json', json_encode($data));
later use it like:
$data = json_decode(file_get_contents(__DIR__.'/cron.json'),true);
if($data !== false) {
}
In WordPress How can I get the URL of the parent post (for a kind of Up button)?
This is the code I'm using to pull the parent name:
<?php
if( empty($wp_query->post->post_parent) ) {
$parent_post_id = $wp_query->post->ID;
} else {
$parent_post_id = $wp_query->post->post_parent;
}
$parent_post = get_post($parent_post_id);
$parent_post_title = $parent_post->post_title;
echo $parent_post_title;
Use get_permalink($postid):
global $post;
$parentId = $post->post_parent;
$linkToParent = get_permalink($parentId);
This is an alternate method I use, which gets the parent page permalink based on the current permalink path instead of the $post->page_parent property:
/**
* Get the parent permalink based on the url path
*
* #param $id int
* #return str
*/
function get_parent_permalink($id = false) {
$id = !$id ? get_the_id() : $id;
return str_replace(basename(get_permalink($id)) . '/', '', get_permalink($id));
}
How to add a link category_id added to the admin? (Joomla 2.5)
You could write in the function JToolBarHelper::addNew('select.add'); or other functions...
For example,
index.php?option=com_pictures&view=select&layout=edit&category_id=14
Help, please. Thanks in advance
Reply David F:
Hi, David F. I almost got it.
After clicking "Add" appears category_id=14, and the rest did not work after clicking "Edit", "Save", "Save Close" ... - category_id=0
I've been programming. Here's an example:
...
protected $catid;
public function __construct($config = array()) {
parent::__construct($config);
if (empty($this->catid)) {
$this->catid = JRequest::getInt('category_id', 0);
}
}
protected function allowAdd($data = array()) {
$user = JFactory::getUser();
$categoryId = JArrayHelper::getValue($data, 'catid', JRequest::getInt('filter_category_id'), 'int');
$allow = null;
if ($categoryId) {
$allow = $user->authorise('core.create', $this->option . '.category.' . $categoryId);
}
if ($allow === null) {
return parent::allowAdd($data);
} else {
return $allow;
}
}
protected function allowEdit($data = array(), $key = 'id') {
$recordId = (int) isset($data[$key]) ? $data[$key] : 0;
$categoryId = 0;
if ($recordId) {
$categoryId = (int) $this->getModel()->getItem($recordId)->catid;
}
if ($categoryId) {
return JFactory::getUser()->authorise('core.edit', $this->option . '.category.' . $categoryId);
} else {
return parent::allowEdit($data, $key);
}
}
protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') {
$append = parent::getRedirectToItemAppend($recordId);
$append .= '&category_id=' . $this->category_id;
return $append;
}
protected function getRedirectToListAppend() {
$append = parent::getRedirectToListAppend();
$append .= '&category_id=' . $this->category_id;
return $append;
}
I believe that the functions that you are looking for are part of JController and should be added to your controller. In your case, this would likely be the select.php controller based on the view name in your url.
You can see a good example of this in the categories component, specifically at administrator/components/com_categories/controllers/category.php.
The following is the code in com_categories. You would want to rename extension to 'category_id' and may want to grab the value from JInput instead of the current class:
/**
* Gets the URL arguments to append to an item redirect.
*
* #param integer $recordId The primary key id for the item.
* #param string $urlVar The name of the URL variable for the id.
*
* #return string The arguments to append to the redirect URL.
*
* #since 1.6
*/
protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id')
{
$append = parent::getRedirectToItemAppend($recordId);
$append .= '&extension=' . $this->extension;
return $append;
}
/**
* Gets the URL arguments to append to a list redirect.
*
* #return string The arguments to append to the redirect URL.
*
* #since 1.6
*/
protected function getRedirectToListAppend()
{
$append = parent::getRedirectToListAppend();
$append .= '&extension=' . $this->extension;
return $append;
}
*EDIT:
You also have to add it as part of the form. This is the easy, but important part. Just make sure the form has a hidden input with the value or add it to the url in the action section of the form:
<form action="<?php echo JRoute::_('index.php?option=com_component&layout=edit&id='.(int) $this->item->id . '&category_id='.$this->category_id); ?>" method="post" name="adminForm">
or use this:
<input type="hidden" name="category_id" value="<?php echo $this->category_id; ?>" />
To further explain what happens, when you click an item to go to the form, you likely add on the variable that you need. Then you add it to the form so that when one of the items is clicked, it will get submitted with the form. Joomla processes this form and either saves it or not depending on the toolbar button clicked. Then Joomla redirects, either back to the form or to the list view. Without the functions in your controller, your variable gets lost.
I would like to make a PHP if condition code that will check if the last 10 articles or 10 minutes from the article reading by the user have already elapsed.
E.g.
A user open a page with id = 235 (this id value is in the url localhost/article/235 )
and this id value will be saved in session with a current timestamp and maybe his IP address
Then he read another article and the same will happen.
I need to remember the clicked stuff for another ten clicks and then reset that only for the first row. E.g. after the 10th click the id and timestamp will not became 11th row but will replace the 1st row in the list.
The php condition in CodeIgniter will then check these values and will update the article hit counter value in the articles table and column counter like this:
$this->db->where('id', $id);
$this->db->set('counter', 'counter+1', FALSE);
$this->db->update('articles');
But before calling this code I need to make this check from the session?
How to do that?
I think storing e.g. 10 entries in the session with timestamps per user will be enough.
Just don't save the same page in the session twice.
And the condition will check the current timestamp with the saved one and if it is more than e.g. 10 minutes or the user have read/clicked another 10 articles it will allow the update counter php code.
I don't need to have this bulletproof. Just to disable the increment using browser's refresh button.
So, if he wants to increment the counter he will need to wait ten minutes or read another 10 articles ;)
You should definitely go for Sessions. It saves you bandwidth consumption and is much easier to handle. Unless, of course, you need the data on the client-side, which, by your explanation, I assume you don't. Assuming you went for sessions, all you gotta do is store an array with the data you have. The following code should do it:
$aClicks = $this->session
->userdata('article_clicks');
// Initialize the array, if it's not already initialized
if ($aClicks == false) {
$aClicks = array();
}
// Now, we clean our array for the articles that have been clicked longer than
// 10 minutes ago.
$aClicks = array_filter(
$aClicks,
function($click) {
return (time() - $click['time']) < 600; // Less than 10 minutes elapsed
}
);
// We check if the article clicked is already in the list
$found = false;
foreach ($aClicks as $click) {
if ($click['article'] === $id) { // Assuming $id holds the article id
$found = true;
break;
}
}
// If it's not, we add it
if (!$found) {
$aClicks[] = array(
'article' => $id, // Assuming $id holds the article id
'time' => time()
);
}
// Store the clicks back to the session
$this->session
->set_userdata('article_clicks', $aClicks);
// If we meet all conditions
if (count($aClicks) < 10) {
// Do something
}
I assumne that $clicks is an array with up to ten visited articles. The id is used as key and the timestamp as value. $id is the id of the new article.
$clicks = $this->session->userdata('article_clicks');
//default value
$clicks = ($clicks)? $clicks : array();
//could be loaded from config
$maxItemCount = 10;
$timwToLive= 600;
//helpers
$time = time();
$deadline = $time - $timeToLive;
//add if not in list
if(! isset($clicks[$id]) ){
$clicks[$id] = $time;
}
//remove old values
$clicks = array_filter($clicks, function($value){ $value >= $deadline;});
//sort newest to oldest
arsort($clicks);
//limit items, oldest will be removed first because we sorted the array
$clicks = array_slice($clicks, 0, $maxItemCount);
//save to session
$this->session->>set_userdata('article_clicks',$clicks)
Usage:
//print how mch time has passed since the last visit
if(isset($clicks[$id]){
echo "visited ".($time-$clicks[$id]). "seconds ago." ;
} else {
echo "first visit";
}
EDIT: you have to use arsort not rsort or the keys will be lost, sorry
Based on Raphael_ code and your question you can try this:
<?php
$aClicks = $this->session
->userdata('article_clicks');
$nextId = $this->session->userdata('nextId');
// Initialize the array, if it's not already initialized
if ($aClicks == false) {
$aClicks = array();
$nextId = 0;
}
// Now, we clean our array for the articles that have been clicked longer than
// 10 minutes ago.
$aClicks = array_filter($aClicks, function($click) {
return (time() - $click['time']) < 600; // Less than 10 minutes elapsed
}
);
// We check if the article clicked is already in the list
$found = false;
foreach ($aClicks as $click) {
if ($click['article'] === $id) { // Assuming $id holds the article id
$found = true;
break;
}
}
// If it's not, we add it
if (!$found) {
$aClicks[$nextId] = array(
'article' => $id, // Assuming $id holds the article id
'time' => time()
);
$nextId++;
$this->session->set_userdata('nextId', $nextId);
}
$this->session->set_userdata('article_clicks', $aClicks);
if (count($aClicks) > 10 && $nextId > 9) {
$this->session->set_userdata('nextId', 0);
echo "OK!";
}
?>
I hope I understood correctly what you need.
Usage:
$this->load->library('click');
$this->click->add($id, time());
The class API is very simple and the code is commented. You can also check if an item expired(), if exists() and you can get() item saved time.
Remember that:
Each item will expire after 10 minutes (see $ttl)
Only 10 items are saved in session (see $max_entries)
class Click
{
/**
* CI instance
* #var object
*/
private $CI;
/**
* Click data holder
* #var array
*/
protected $clicks = array();
/**
* Time until an entry will expire
* #var int
*/
protected $ttl = 600;
/**
* How much entries do we store ?
* #var int
*/
protected $max_entries = 10;
// -------------------------------------------------------------------------
public function __construct()
{
$this->CI =& get_instance();
if (!class_exists('CI_Session')) {
$this->CI->load->library('session');
}
// load existing data from user's session
$this->fetch();
}
// -------------------------------------------------------------------------
/**
* Add a new page
*
* #access public
* #param int $id Page ID
* #param int $time Added time (optional)
* #return bool
*/
public function add($id, $time = null)
{
// If page ID does not exist and limit has been reached, stop here
if (!$this->exist($id) AND (count($this->clicks) == $this->max_entries)) {
return false;
}
$time = !is_null($time) ? $time : time();
if ($this->expired($id)) {
$this->clicks[$id] = $time;
return true;
}
return false;
}
/**
* Get specified page ID data
*
* #access public
* #param int $id Page ID
* #return int|bool Added time or `false` on error
*/
public function get($id)
{
return ($this->exist($id)) ? $this->clicks[$id] : false;
}
/**
* Check if specified page ID exists
*
* #access public
* #param int $id Page ID
* #return bool
*/
public function exist($id)
{
return isset($this->clicks[$id]);
}
/**
* Check if specified page ID expired
*
* #access public
* #param int $id Page ID
* #return bool
*/
public function expired($id)
{
// id does not exist, return `true` so it can added
if (!$this->exist($id)) {
return true;
}
return ((time() - $this->clicks[$id]) >= $this->ttl) ? true : false;
}
/**
* Store current clicks data in session
*
* #access public
* #return object Click
*/
public function save()
{
$this->CI->session->set_userdata('article_clicks', serialize($this->clicks));
return $this;
}
/**
* Load data from user's session
*
* #access public
* #return object Click
*/
public function fetch()
{
if ($data = $this->CI->session->userdata('article_clicks')) {
$this->clicks = unserialize($data);
}
return $this;
}
public function __destruct()
{
$this->save();
}
}
You could easily wrap that into a class of it's own that serializes the information into a string and that is able to manipulate the data, e.g. to add another value while taking care to cap at the maximum of ten elements.
A potential usage could look like, let's assume the cookie last would contain 256 at start:
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(10), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(20), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(30), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(40), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(50), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(60), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(70), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(80), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(90), "\n";
echo $_COOKIE['last'] = (new StringQueue($_COOKIE['last']))->add(100), "\n";
And the output (Demo):
10,256
20,10,256
30,20,10,256
40,30,20,10,256
50,40,30,20,10,256
60,50,40,30,20,10,256
70,60,50,40,30,20,10,256
80,70,60,50,40,30,20,10,256
90,80,70,60,50,40,30,20,10,256
100,90,80,70,60,50,40,30,20,10
A rough implementation of that:
class StringQueue implements Countable
{
private $size = 10;
private $separator = ',';
private $values;
public function __construct($string) {
$this->values = $this->parseString($string);
}
private function parseString($string) {
$values = explode($this->separator, $string, $this->size + 1);
if (isset($values[$this->size])) {
unset($values[$this->size]);
}
return $values;
}
public function add($value) {
$this->values = $this->parseString($value . $this->separator . $this);
return $this;
}
public function __toString() {
return implode(',', $this->values);
}
public function count() {
return count($this->values);
}
}
It's just some basic string operations, here with implode and explode.