How do I correctly create a Zend Feed? - php

I have successfully created a simple RSS feed, but entries keep coming back as unread and updated, and entries deleted from the client reappear everytime I ask mail to update the feed.
What am I doing wrong?
I use this simple function to create an rss feed:
public static function getFeed($db)
{
$title = 'Latest feeds';
$feedUri = '/rss/';
//link from which feed is available
$link = 'http://' . $_SERVER['HTTP_HOST'] . $feedUri;
//create array according to structure defined in Zend_Feed documentation
$feedArr = array('title' => $title,
'link' => $link,
'description' => $title,
'language' => 'en-us',
'charset' => 'utf-8',
//'published' => 1237281011,
'generator' => 'Zend Framework Zend_Feed',
'entries' => array()
);
$itemObjs = array();
$select = $db->select('id')->from('things')
->order('createddate desc')
->limit(10);
$results = $db->fetchAll($select->__toString());
$count = count($results);
for($i=0;$i<$count;$i++) {
$itemObjs[] = SiteUtil::getItemObjectInstance($db, $results[$i]['id']);
}
$count = count($itemObjs);
for($i=0;$i<$count;$i++) {
$obj = & $itemObjs[$i];
$feedArr['entries'][] = array('title' => $obj->getSummary(),
'link' => 'http://' . $_SERVER['HTTP_HOST'] . $obj->getDetailUri(),
'description' => $obj->description,
'publishdate' => $obj->publishedDate,
'guid' => 'http://' . $_SERVER['HTTP_HOST'] . $obj->getDetailUri()
);
}
$feed = Zend_Feed::importArray($feedArr, 'rss');
return $feed;
}
The action in the controller class is:
public function rssAction()
{
$feed = FeedUtil::getFeed($this->db);
$feed->send();
}
So to access the feed, I point the client to:
http://mysite.com/rss
I am using mac mail's rss client to test. The feed downloads just fine, showing all 5 items I have in the database for testing purposes. The problems are as follows:
1) If I mark one or more items as 'read' and then tell mail to update the feed, it pulls all items again as if I never downloaded them in the first place.
2) If I delete one or more items they come back again, unread, again as if it were the first time I subscribed to the feed.
3) Feeds are always marked as updated. Is that supposed to be the case?
Is is something to do with the parameters I'm setting, am I omitting something, or could the solution be something more subtle like setting HTTP content headers (e.g. '304 Not Modified')?
My understanding of rss is that once an item has been marked as read or deleted from the client, it should never come back, which is the behaviour I'm after.
Just to note, the 'link' and 'guid' parameters are always unique, and I have tried experimenting with 'published' and 'publishdate' (both optional) attributes only get the same result. The above code is a simplified version of what I have, showing only the relevant bits, and finally, yes, I have read the rss specification.
Thanks in advance for any help offered here, I'll be happy to clarify any point.

According to the Zend Framework Doc, you must use the lastUpdate parameter to set the last modification date of an entry.
'entries' => array(
array(
[...]
'lastUpdate' => 'timestamp of the publication date', // optional
[...]
So published for the feed, and lastUpdate for the entries.

Related

PHP - For each loop does not always do all iterations

Currently, I have the following problem:
I have created a WordPress environment that sends personalized emails to subscribers based on their preferences. This has worked for quite some time but for a couple of months, we are experiencing some inconsistencies. These inconsistencies are as followed:
Once in a while, the foreach loop for sending the emails stops in the middle of its execution. For example, we have a newsletter with 4000 subscribers. Once in a while, the program randomly stops its sending procedure at around 2500 emails. When this happens, there are literally no signs of any errors and there is also nothing to be seen in the debug log.
I have tried the following things to fix the issue:
Different sender; we switched from Sendgrid to SMTPeter (Dutch SMTP service)
Delays; we have tried whether placing a wait after x number of emails would have any impact because there might be too many requests per minute, but this was not the case.
Disable plugins; For 5 weeks we thought we had found the problem. WordFence seemed to be the problem, unfortunately, the send function stopped again last week and this did not appear to be causing the problems. Just to show how unstable it really is. It can go well for 5 weeks and then not for 2 weeks.
Rewriting of functions
Logging, we write values ​​to a txt file after every important step to keep track of where the send function stops. This is just to see which users have received an email and which still need to receive it so that we can continue sending it from there.
Debug log, the annoying thing is that even when we have the wp_debug on, nothing comes up that indicates a cause of crashing.
To schedule the sender I use the WP_Cron to run the task in the background. From there the following function is triggered;
Below, the code I wrote in stripped format. I removed all the $message additions as this is just HTML with some variables of ACF for the email. I translated it so it's easier to understand.
<?php
function send_email($edition_id, $post)
{
require_once('SMTPeter.php'); //Init SMTPeter Sender
$myfile = fopen("log.txt", "a") or die("Unable to open file!"); //Open custom logfile
$editionmeta = get_post_meta($edition_id); //Get data of edition
$users = get_users();
$args = array(
'post_type' => 'articles',
'post_status' => 'publish',
'posts_per_page' => -1,
'order' => 'asc',
'meta_key' => 'position',
'orderby' => 'meta_value_num',
'meta_query' => array(
array(
'key' => 'edition_id',
'value' => $edition_id,
'compare' => 'LIKE',
),
),
);
$all_articles = new WP_Query($args); // Get all articles of edition
$i = 0; // Counter users interrested in topic
$j = 0; // Counter sent emails
foreach ($users as $user) { //Loop over all users <---- This is the loop that not always finishes all itterations
$topic_ids = get_field('topicselect_', 'user_' . $user->ID);
$topic_id = $editionmeta['topic_id'][0];
if (in_array($editionmeta['topic_id'][0], $topic_ids)) { // Check if user is interrested in topic.
$i++; // Counter interrested in topic +1.
// Header info
$headerid = $editionmeta['header_id'][0];
$headerimage = get_field('header_image', $headerid);
$headerimagesmall = get_field('header_image_small', $headerid);
// Footer info
$footerid = $editionmeta['footer_id'][0];
$footer1 = get_field('footerblock_1', $footerid);
$footer2 = get_field('footerblock_2', $footerid);
$footer3 = get_field('footerblock_3', $footerid);
$message = '*HTML header newsletter*'; // First piece of content email
if ($all_articles->have_posts()) :
$articlecount = 0; // Set article count to check for empty newsletters
while ($all_articles->have_posts()) : $all_articles->the_post();
global $post;
$art_categories = get_the_category($post->ID); // Get categories of article
$user_categories = get_field('user_categories_', 'user_' . $user->ID); // Get categories user is interrested in
$user_cats = array();
foreach ($user_categories as $user_category) {
$user_cats[] = $user_category->name; // right format for comparison
}
$art_cats = array();
foreach ($art_categories as $art_category) {
$art_cats[] = $art_category->name; // right format for comparison
}
$catcheck = array_intersect($user_cats, $art_cats); // Check if 1 of the article's categories matches one of a user's categories
if (count($catcheck) > 0) { // The moment the array intersect count is greater than 0 (at least 1 category matches), the article is added to the newsletter.
$message .= "*Content of article*"; // Append article to content of newsletter
$articlecount++;
}
endwhile;
endif;
if ($articlecount > 0) { //As soon as the newsletter contains at least 1 article, it will be sent.
$j++; //Sent email counter.
$mailtitle = $editionmeta['mail_subject'][0]; // Title of the email
$sender = new SMTPeter("*API Key*"); // Class SMTPeter sender
$output = $sender->post("send", array(
'recipients' => $user->user_email, // The receiving email address
'subject' => $mailtitle, // MIME's subject
'from' => "*Sender*", // MIME's sending email address
'html' => $message,
'replyto' => "*Reply To*",
'trackclicks' => true,
'trackopens' => true,
'trackbounces' => true,
'tags' => array("$edition_id")
));
error_log(print_r($output, TRUE));
fwrite($myfile, print_r($output, true));
}
}
}
fclose($myfile);
}
All I want to know is the following;
Why can't my code run the foreach completely, every time? I mean, it's quite frustrating to see that it sometimes works like a charm, and the next time it could get stuck again.
Some things I thought about but did not yet implement:
Rewrite parts of the function into separate functions. Retrieving the content and setting up the HTML for the newsletter could be done in a different function. Besides the fact that it would obviously be an improvement for cleaner code, I just wonder if this could actually be the problem.
Can a foreach crash due to a fwrite trying to write to a file that is already being written to? So does our log cause the function to not run properly? (Concurrency, but is this a thing in PHP with its workers?)
Could the entire sending process be written in a different way?
Thanks in advance,
Really looking forward to your feedback and findings

How to return a variable operator like $option[];

Obviously, I can't do this, but is there some way to achieve what I am trying to? I only found can not do's online, but no potential workarounds.
Here is what I am trying to do.
Currently I get the following error... "Cannot use [] for reading"
For my theme, I have a framework and the fields from that framework are built using an array that I create.
It looks something like this (minus the 300+ lines of code that I actually use)...
$options[] =
array(
'title' => 'This Field Tab Title',
'name' => 'this-field-tab-slug',
'fields' =>
array(
// ----------------------------------------------------------------------
// This Field Option Name
// ----------------------------------------------------------------------
array(
'type' => 'this_field_type',
'id' => 'this_field_types_id',
),
// ----------------------------------------------------------------------
// This Field Option Name
// ----------------------------------------------------------------------
array(
'type' => 'this_field_type',
'id' => 'this_field_types_id',
),
// ----------------------------------------------------------------------
// This Field Option Name
// ----------------------------------------------------------------------
array(
'type' => 'this_field_type',
'id' => 'this_field_types_id',
),
),
);
I am running a grouped field type, so my output has many options/fields within this grouped field/area which can then be added again and again as many times as the user needs. Then I am repeating that whole process/code again but for other taxonomies of the user's site.
So for example, the whole process above applies to post types, categories, tags, archived, etc. etc. So instead of having thousands of lines of repetitive codes, I'm trying to create my own function and pass the variables to that function.
But for the function, I find I can't return $options[];
Here is a screenshot of what I mean by the grouped field that can be added as many times as the user needs.
And here's an example of the function I am trying to create!
public static function layout_settings_config($title_name = '', $title_slug = '', $title_id = '', $query = '') {
$title_name = 'Post Type';
$title_slug = 'post-type';
$title_id = 'post_type';
$query = 'post_types';
$options[] =
array(
// all the config array codes in here...
);
return $options ??? $options[]; doesn't work.
}
Is this possible to achieve what I am trying to a different way? I'm still a little new to creating my own functions and OOP, but nothing I find online for this specific issue with a workaround.
Thanks!
$options[] is not object but it is an operation like function.
You should return $options instead.
and, by the way, when you say $options[] = something. it actually insert something inside an array called $option. so effectively you have to access your options like this.
$option[0]->title.
So I suggest Instead of making it complex like this. simply say
$option = something.

Can't update subscriber information Aweber API PHP

I'm trying to update Aweber subscriber information, specifically the custom fields and I'm using Aweber API but it's not working and probably I'm not writing correctly the code:
require_once('../AweberAPI/aweber_api/aweber_api.php');
include("../config.php");
$email=$_POST["email"];
$threefears=$_POST["3fears"];
$handlefears=$_POST["handlefears"];
$threeactions=$_POST["3actions"];
$changelife=$_POST["changelife"];
$consumerKey = '';
$consumerSecret = '';
$accessKey = '***'; # put your credentials here
$accessSecret = '***'; # put your credentials here
$account_id = ''; # put the Account ID here
$list_id = ''; # put the List ID here
$aweber = new AWeberAPI($consumerKey, $consumerSecret);
try {
$custom_field->name = 'Favorite Color';
$custom_field->save();
$params = array('email' => '$email');
$found_subscribers = $account->findSubscribers($params);
foreach($found_subscribers as $subscriber) {
$subscriber->custom_fields = array(
'Top 3 biggest fears related to dating' => '$threefears',
'How would the person you most admire handle these fears' => '$handlefears',
'What are 3 actions you can take today to act more like the person you most admire' => '$threeactions',
'How will taking these actions change your attitude towards dating and your life' => '$changelife',
);
$subscriber->save();
}
}
The custom fields you are submitting must already exist on your list before you can submit them via the API. This can be done within your aweber control panel using this process: https://help.aweber.com/hc/en-us/articles/204027516-How-Do-I-Create-Custom-Fields-
So if you created a custom field named 'age' then your code would look something like this (assuming an existing $subscriber object):
$fields = array(
'age' => '21',
);
$subscriber->custom_fields = $fields;
$subscriber->save();
or
$subscriber['custom_fields']['age'] = '21';
$subscriber->save();
I guess that instead of writing the values you are writing $threefears, $handlefears etc as text.
In your example you are putting variables as '$variable' instead of just $variable. That would write variable name instead of variable content.
so, instead of
$subscriber->custom_fields = array(
'Top 3 biggest fears related to dating' => '$threefears',
'How would the person you most admire handle these fears' => '$handlefears',
'What are 3 actions you can take today to act more like the person you most admire' => '$threeactions',
'How will taking these actions change your attitude towards dating and your life' => '$changelife',
);
try
$subscriber->custom_fields = array(
'Top 3 biggest fears related to dating' => $threefears,
'How would the person you most admire handle these fears' => $handlefears,
'What are 3 actions you can take today to act more like the person you most admire' => $threeactions,
'How will taking these actions change your attitude towards dating and your life' => $changelife
);
Note that even stackoverflow is correctly hightlighting variable names now.
And for Pete's sake, make the custom field's names shorter :) Most certainly there is a limit on the post you can make. Having such long variable name makes for less space in variable value, per post.
Oh and delete
$custom_field->name = 'Favorite Color';
$custom_field->save();
And modify from
$params = array('email' => '$email');
to
$params = array('email' => $email);
or to
$params = array('email' => $email, 'status' => 'subscribed');
It is correct that the custom fields you are submitting must already exist on your list before you can submit them via the API. This can be done within your aweber control panel using this process: https://help.aweber.com/hc/en-us/articles/204027516-How-Do-I-Create-Custom-Fields-
after creating a custom field named 'age' , the php code will be like this
$fields = array(
'age' => '21',
);
$subscriber->custom_fields = $fields;
$subscriber->save();

Drupal: use view output as node content

I'm writing a Drupal 7 module to display child nodes of a module in the content.
Nodes have a field parent_nodes (node reference) where one ore more nodes are selected as parents.
First, I've created a view projects with a block view display subprojects, displaying nodes of type project with a field_parent_project contextual filter.
This is my module:
<?php
function projects_preprocess_node(&$variables) {
if ($variables['type'] == 'project') {
if (isset($variables['view_mode']) && $variables['view_mode'] == 'full') {
_projects_add_subprojects($variables);
}
}
}
function _projects_add_subprojects(&$variables) {
$nid = $variables['nid'];
$view = views_get_view('projects');
$preview = $view->preview('subprojects', array($nid));
$subprojects = array(
'#title' => t('Subprojects'),
'#label_display' => 'above',
'#weight' => 10,
//'#theme' => 'field',
'#markup' => $preview,
);
if (!isset($variables['content']['subprojects'])) {
$variables['content']['subprojects'] = array();
}
$variables['content']['subprojects'][] = $subprojects;
dpm($variables['content']);
}
This is working, adding the view display output to the node's content.
Only some things aren't working:
title (label)
weight do not change display position when rendered with other contents (it's always the first, above body).
If I uncomment the '#theme' => 'field' line, title is shown as a label, but nothing is rendered. This is because the field theme is used and I guess it needs #items and does not use the #markup element.
I cannot use a children nodes as reference, but only parent nodes.
The solution must be independent to theme, so no not answer "change your theme template" or similar
How can I show children nodes in node? I'm looking for a way to get something interpretable how a it is was a field
If you didn't already know, the Viewfield module allows you to specify a View as a field in your content type. This may save you some coding but you may not want a whole module to do such a specific task so...
If you want to continue with the custom code which you've written, then you need to re-structure your added content to the correct render array structure that Drupal expects. Try something like this:
$subprojects_view_output = array(
'#type' => 'markup',
'#markup' => $preview,
);
$subprojects = array(
'#theme' => 'field',
'#weight' => 10,
'#title' => t('Subprojects'),
'#items' => $subprojects_view_output,
);
With the above, the title/label for your field as well as the content of the field (the view itself) should show up. The code is untested so may not be 100% correct in terms of syntax and all but hopefully gives you a path to a solution.
EDIT: I tested the above and it does not work because in order to use the existing theme_field function it seems that Drupal expects more information required to render a field like the #field_name, #field_type, #entity_type, etc. as you should see in the warning messages.
Essentially, you are faking a field and you will need to provide Drupal with all the info it expects if you want to continue to use the built-in theme_field function, including all the variables as expected in the preprocess functions.
Alternatively, you can continue to use your original code and add a #prefix to get your title/label to render like this:
$subprojects = array(
'#weight' => 10,
'#prefix' => '<div id="subprojects-view">asdf:</div>',
//'#theme' => 'field',
'#markup' => $preview,
);
Then style the title/label with CSS accordingly. I didn't have any problems with the weighting as you described.
Thanks to #nmc, this is my final solution. If no results are found, it does not display the title. The check for results is done by if (count($view->result) == 0). Weight is working.
<?php
function projects_preprocess_node(&$variables) {
$type = $variables['type'];
if ($type == 'project' || $type == 'customer') {
if (isset($variables['view_mode']) && $variables['view_mode'] == 'full') {
_projects_add_subprojects_markup($variables);
}
}
}
function _projects_add_subprojects_markup(&$variables) {
$nid = $variables['nid'];
$view = views_get_view('projects');
$preview = $view->preview('subprojects', array($nid));
if (count($view->result) == 0) {
return;
}
$variables['content']['subprojects'] = array(
'#weight' => 10,
'#prefix' => '<h2>' . t('Subprojects') . '</h2>',
'#markup' => $preview,
);
}

Tagging friends in status update with php

If you post a status update or share a link on facebook there is an option to tag your friends as being 'with you'. It's not the same as tagging them with # symbols.
here is an example: http://www.facebook.com/karin.ohara.98/posts/111246132363889
It shows the person being with alison frasier
I'm trying to code this myself in php. It works for normal status updates. First I get the friend list and then try to add a 'with' parameter. Using chrome web developer tools didn't give much info as to how facebook does this. Doesn't work
shuffle($friends);
$with = array();
for($i = 0; $i < 2; $i++)
{
if($i < count($friends))
array_push($with, array("tag_uid" => $friends[$i]));
}
$fields = array('name' => $status['title'],
'message' => $status['message'],
'caption' => $status['caption'],
'with' => json_encode($with)),
'description' => $status['desc'],
'link' => $url,
'picture' => $status['img']);
$result = HTTP_POST("https://graph.facebook.com/" . $account->id . "/feed?access_token=$access_token", // full URL to query
First I get the friend list and then try to add a 'with' parameter.
There is no “with” parameter when creating a post.
To tag users as being with the poster you have to use the tags parameter – as it is clearly described here, https://developers.facebook.com/docs/reference/api/user/#posts
Note that you will also have to specify a place for this to work.

Categories