I am working on a Wordpress project where I need to dynamically create a function (depending on which kind of template is used for a page or post) that retrieves the comments of each page in question.
So let's say I have pages within Wordpress with the IDs 100, 110, 120, 130, 140, 150 and out of these 3 are using the template called "blog" (e.g.: 100, 130 and 150).
So in order to retrieve the comments from these 3 pages with AJAX I need to create a function for each of them:
function GetComments100() { #### }
function GetComments130() { #### }
function GetComments150() { #### }
Here's the function code I need to create individually for each page (and which goes in between the function brackets above (instead of the ####):
$defaults = array( 'order' => 'DESC', 'post_id' => $functionID, 'post_type' => 'page', 'count' => false );
$comments = get_comments($defaults);
foreach($comments as $comment) :
echo "<div class='table-row' style='margin-bottom:1px'><div class='table-cell-1' style='width:110px;'>".$comment->comment_author.":</div><div class='table-cell-2'style='width:870px;'>".$comment->comment_content." <em><a>".$comment->comment_date." ... ".get_the_title($comment->comment_post_ID)." (".$comment->comment_post_ID.")</a></em></div></div>";
endforeach;
die($results);
In order to get the pages I use a loop-function which gives me the page ID as a variable (in my case its $functionID (also included in the array of my function above)).
I have already managed to dynamically create the functions with the following lines of code (I know "eval" is not a good choice but I didn't find any other solution):
$string = 'function ' . $functionName . "() {
####
}";
eval($string);
Now instead of the #### I need to integrate the actual function code starting with "$defaults = array(..." but obviously it has to be completely converted to a string - which is what I am struggling with.
Any help would be appreciated (again, I know using "eval" is not nice but so far I didn't find any other solution for this)
Have you tried using nowdoc for the function body? If you just need expanding $functionName, you can try something like this:
$string="function {$functionName}(){".<<<'END'
$defaults = array( 'order' => 'DESC', 'post_id' => $functionID, 'post_type' => 'page', 'count' => false );
$comments = get_comments($defaults);
foreach($comments as $comment) :
echo "<div class='table-row' style='margin-bottom:1px'><div class='table-cell-1' style='width:110px;'>".$comment->comment_author.":</div><div class='table-cell-2'style='width:870px;'>".$comment->comment_content." <em><a>".$comment->comment_date." ... ".get_the_title($comment->comment_post_ID)." (".$comment->comment_post_ID.")</a></em></div></div>";
endforeach;
die($results);
}
END;
eval($string);
I don't understand why you don't use one function per Template with a parameter like this:
public function getBlogComments($id){
//...
}
or one function which check the used Template
public function getComments($id){
// get Template of $id
//...
}
Related
Ive been stressing alot with this php code and cant figure out why it does not work.. Stack overflow is kind of the my last resort.
First things first, here is my code:
$avar = "Name";
$args = array(
'category_name' => $avar
);
var_dump($args);
This code returns:
array (size=1)
'category_name' => null
So the question is, why doesnt it return "Name" instead of null and is there any way to give the array the value of the variable?
Please help me!
** Update **
Im sorry. Forgot I had the code inside a function. Here is the code I use. I put it inside a brand new document, and it still doesnt work. Only difference is now i get an error. (Im coding for wordpress, and i guess some warnings are disabled in order to tighten security). The code:
<?php
$avar = "SomeText";
function theFunction() {
$args = array(
'category_name' => $avar
);
var_dump($args);
}
theFunction();
?>
The code still works with strings.
<?php
$avar = "SomeText";
function theFunction() {
global $avar;
$args = array(
'category_name' => $avar
);
var_dump($args);
}
theFunction();
?>
I'm trying to get a list with all registered sidebars using $wp_registered_sidebars but the global variable returns an empty array.
function get_sidebars() {
global $wp_registered_sidebars;
$sidebar_options = array();
foreach ($wp_registered_sidebars as $sidebar)
{
$sidebar_options[$sidebar['id']] = $sidebar['name'];
}
return $sidebar_options;
}
$fields['sidebar_settings'] = array(
'active' => array(
...
'values' => get_sidebars(),
...
),
);
Why is the global variable empty and is there another way to store all registered sidebars in an array?
Please try this
https://wordpress.stackexchange.com/questions/13450/list-all-sidebar-names
you get all the sidebar name lists
Heres some functions that you could be looking for:
dynamic_sidebar
wp_get_sidebars_widgets
See this: http://codex.wordpress.org/Sidebars . There's also some good information.
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,
);
}
So, in order to get this code working, I need to output the function "get_flickr_rss" via a return rather than an echo... I believe the reason this code is not working for me is because the "get_flickr_rss" function itself is somehow defaulting to an echo rather than a return. How can I call the function to force it to return rather than echoing?
function generate_flickr_rss($atts, $content = null) {
// default parameters
extract(shortcode_atts(array(
'set' => '72157625809767439',
'photos' => '20'
), $atts));
// Call FLickrRSS Hook
return get_flickrRSS(array('set' => $set, 'num_items' => $photos, 'type' => 'set'));
}
I tried the following code to reverse engineer it as a return, but unfortunately, no dice.
function generate_flickr_rss($atts) {
// default parameters
extract(shortcode_atts(array(
'set' => '72157625809767439',
'photos' => '20'
), $atts));
// Call FLickrRSS Hook
$flickr_rss_return = get_flickrRSS(array('set' => $set, 'num_items' => $photos, 'type' => 'set'));
return $flickr_rss_return;
}
add_shortcode('flickr_rss', 'generate_flickr_rss');
add_shortcode('flickr_rss', 'generate_flickr_rss');
With output buffering you can catch the output of the function.
ob_start();
get_flickrRSS(...);
return ob_get_clean();
Of course you should rather change the function to return it's output, but I guess that's impossible for a reason. ;-)
I took a look at the WP plugin flickrRSS and the changes aren't that great.
In the function printGallery, there are a number of echo statements. Replace these with lines that concatenate the echoed string to a $result variable that your define as an empty string at the beginning of the function.
Then, return $result at the end of the printGallery function. Then, modify get_flickrRSS to return or echo this string according to your needs (as defined by another input parameter).
Of course, all of this will get overwritten the next time the plugin is updated, so I suggest pointing the plugin writer to this Stack Overflow page and asking him to modify the plugin to support your needs long term :)
$foo = get_flickrRSS(.....;
return $foo;
I want to do something very straight forward and simple. I want to have two different sets of paginated data on the same page. The two different sets depend on different models. For discussion's sake we'll say they are Image and Item.
I can set up two pagers for two models, and get the correct set of objects. I can get the correct pager links. But when it comes to actually following the links to the parameters, both pagers read the parameters and assume they apply to them.
It winds up looking something like this:
$this->paginate = array (
'Item'=>array(
'conditions'=>array('user_id'=>$id),
'limit' => 6,
'order' => array(
'Item.votes'=>'desc',
'Item.created'=>'desc'
),
'contain'=>array(
'User',
'ItemImage' => array (
'order'=>'ItemImage__imageVotes desc'
)
)
),
'Image'=>array(
'limit'=>6,
'contain'=>array(
'User',
'ItemImage'=>array('Item'),
),
'order'=>array(
'Image.votes'=>'desc',
'Image.views'=>'desc'
),
'conditions'=>array(
'Image.isItemImage'=>1,
'Image.user_id'=>$id
)
)
);
$this->set('items', $this->paginate('Item'));
$this->set('images', $this->paginate('Image'));
That's in the controller. In the view I have sort links that look like this:
<div class="control"><?php echo $this->Paginator->sort('Newest', 'Image.created', array('model'=>'Image')); ?></div>
However, that yields a link that looks like this:
http://localhost/profile/37/page:1/sort:Image.created/direction:asc
There's nothing in there to tell the paginator which model I intend to sort. So when I click on the link it attempts to sort both models by Image.created. The result is an error, because Item cannot be sorted by Image.created. Is there something I'm doing wrong? Or is this something that isn't supported by CakePHP's paginator?
You'll need to override the paginate method for the Model of the Controller of that page.
I did something similar, maybe this snippet will help:
function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array())
{
$pageParams = compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive', 'group');
$this->contain('ModuleType', 'NodeDescriptor');
$pageItems = $this->find('all',$pageParams);
$pagesOut = array();
foreach($pageItems as $pageItem)
{
$status = $pageItem['SiteAdmin']['status_id'];
$moduleInfo = null;
$nodeTitle = $pageItem['NodeDescriptor']['title'];
$published = $pageItem['NodeDescriptor']['published'];
$pageitemID = $pageItem['SiteAdmin']['id'];
$moduleId = $pageItem['SiteAdmin']['module_id'];
$contName = $pageItem['ModuleType']['controller'];
if($moduleId)
{
$thisModel = ClassRegistry::getObject($moduleType);
$thisModel->contain();
$moduleInfo = $thisModel->read(null,$moduleId);
$moduleInfo = $moduleInfo[$moduleType];
}
$pagesOut[] = array(
'status'=>$status,
'node'=>$nodeTitle,
'published'=>$published,
'info'=>$moduleInfo,
'module_id'=>$moduleId,
'contName'=>$contName,
'pageitem_id'=>$pageitemID);
}
return $pagesOut;
}
By doing it this way, you gain control over the parameters passed to paginate, so you can pass model specific data, control flags etc.
The easiest solution would be to implement both grids as elements that fetch their own data and use AJAX to load the elements into the page.
The only other option would be to modify the params so you pass the params for both grids to each grid when sorting or stepping through pages. The code posted by Leo above is a good start. You can prepend the Model key from the paginate array onto each named param and make sure you pass all url params to the paginate function and you should be headed in the right direction.