I have this foreach loop wich shows the supporters located in the post_meta from a custom post type. What I want to do is add pagination to the foreach loop. I have already found a way to decide how many supporters are shown by slicing the array, but now I am at a loss. And have no idea how to proceed.
Function to get the supporters array
function getSupporters($petitieID){
$support = get_post_meta(get_the_ID(), 'supporters', true);
if (!empty($support)){
return $support;
}}
Function to show the individual supporters in the array
function showSupporters($petitieID){
$supporters = getSupporters($petitieID);
if (!empty($supporters)){
foreach (array_slice($supporters, 0, 2) as $supporter){
$supporterID = $supporter->post_author;
the_author_meta('first_name', $supporterID);
}
}else {
echo 'no votes';
}
}
You could determine which page is currently shown in a GET variable in your address
.../supporters.php?page=1
Then you could set the offset of your array_slice function accordingly
$nItemsPerPage = 2;
$page = isset($_GET['page'])?$_GET['page']:1;
array_slice($supporters, $nItemsPerPage*($page-1), $nItemsPerPage)
Related
In my WordPress child theme workspace, I am trying to learn how to optimize my code below to be more efficient in its PHP process. I have 10 images total that I'm working with. I want any number of these images to be called onto different pages by slug. I know in PHP how to return once from a function, but how do I say in PHP...
"I want photos 1, 2, 6 to go to slugA"
"I want photos 2, 3, 5, 9 to go to slugB"
"I want photos 1, 7 to go to slugC"
etc...
This is what I have so far
//DEFINING ALL MY PHOTOS AND RETURNING THEM
function my_post_photos (
$mQuery = 1,
$image01 = "filler_01.jpg",
$image02 = "filler_02.jpg",
$image03 = "filler_03.jpg",
$image04 = "filler_04.jpg",
$image05 = "filler_05.jpg",
$image06 = "filler_06.jpg",
$image07 = "filler_07.jpg",
$image08 = "filler_08.jpg",
$image09 = "filler_09.jpg",
$image10 = "filler_10.jpg"
): string
{
$vars = get_defined_vars();
foreach ($vars as $key => $value) {
$placeholders[] = get_stylesheet_directory_uri() . '/dist/images/' . $value;
}
return $placeholders[$mQuery];
}
//FURTHER DOWN THIS SAME PAGE...WITHIN MY WP LOOP, CALLING THEM
<?php
$query = new WP_Query($args);
if ($query->have_posts()) :
//WITH THE BELOW $i, I AM FULLY AWARE THAT THE NUMBER OF PHOTOS LOADS IS DEPENDENT ON HOW MANY TIMES MY LOOP CYCLES. I'M COOL WITH THAT BECAUSE I'M EVENTUALLY GOING TO HAVE MORE PHOTOS THAN POSTS.
$i=1;
while ($query->have_posts()) : $query->the_post();
$current_page = sanitize_post($GLOBALS['wp_the_query']->get_queried_object());
$slug = $current_page->post_name;
?>
<?php
if ($slug == "slugA") {
?>
<div>
<h6>
<!-- //THIS FUNCTION LOADS EACH PHOTO PERFECTLY FINE, BUT HOW CAN I ONLY RETURN PHOTOS 1, 2, 6 HERE? -->
<img src="<?php echo my_career_placeholder($i); ?>" border="0" alt="">
</h6>
</div>
<?php
} elseif ($slug = "slugB") {
//HOW CAN I RETURN ONLY PHOTOS 2, 3, 5, 9 HERE?
} elseif ($slug = "slugC") {
//HOW CAN I RETURN ONLY PHOTOS 1, 7 HERE?
}
?>
<?php
$i++;
endif;
endwhile;
endif;
wp_reset_postdata();
?>
Looking at your code as a whole, I think your main function could be rewritten as follows:
function my_post_photos(...$indexes): array
{
$pathPrefix = get_stylesheet_directory_uri().'/dist/images/';
$placeholders = [
$pathPrefix.'filler_01.jpg',
$pathPrefix.'filler_02.jpg',
$pathPrefix.'filler_03.jpg',
$pathPrefix.'filler_04.jpg',
$pathPrefix.'filler_05.jpg',
$pathPrefix.'filler_06.jpg',
$pathPrefix.'filler_07.jpg',
$pathPrefix.'filler_08.jpg',
$pathPrefix.'filler_09.jpg',
$pathPrefix.'filler_10.jpg',
];
$ret = [];
foreach ($indexes as $index) {
if (isset($placeholders[$index])) {
$ret[] = $placeholders[$index];
}
}
return $ret;
}
This would allow you to call it and pass as many indexes in as you want by doing my_post_photos(3,5), which would return an array that you could loop over.
Demo here: https://3v4l.org/8aq6d
Additional optimizations could be done if you truly name your images in that consistent manner, but I'm just keeping this simple for now.
edit
Based on your comments, I think you want to call the function in the loop and get the "next" item, but for the specific slug.
If that's right, one way to do this would be to create a second array that maps slugs to image indexes. You can then use static with that array which means that subsequent calls to the function won't recreate the array, but instead use the first one. Lastly, you can use array_shift which gets you the first item from an array and actually removes that index from the array. (The function array_shift is considered non-performant for large arrays, if I understand things correctly, but I don't think you'll notice that here at all.)
The code below changes this back to returning a string (or null), and can be called repeatadly with a known-slug to get the "next" item. If you'd ever have more posts than images you could take the "next" and append it to the end of the array giving you a circular pool, too.
function my_post_photos(string $slug): ?string
{
$pathPrefix = get_stylesheet_directory_uri().'/dist/images/';
$placeholders = [
$pathPrefix.'filler_01.jpg',
$pathPrefix.'filler_02.jpg',
$pathPrefix.'filler_03.jpg',
$pathPrefix.'filler_04.jpg',
$pathPrefix.'filler_05.jpg',
$pathPrefix.'filler_06.jpg',
$pathPrefix.'filler_07.jpg',
$pathPrefix.'filler_08.jpg',
$pathPrefix.'filler_09.jpg',
$pathPrefix.'filler_10.jpg',
];
// Mapping of slugs to placeholders
// NOTE: This array is created static so that it only ever
// gets created once in the lifetime of the PHP request
static $slugToPlaceholders = [
'slugA' => [1, 2, 6],
'slugB' => [2, 3, 5, 9],
'slugC' => [1, 7],
];
// Unknown slug, return null
if(!isset($slugToPlaceholders[$slug])){
return null;
}
// Grab the next unused index, and remove it from the array
$nextIndex = array_shift($slugToPlaceholders[$slug]);
// Return either the image or nothing if we're out of indexes
return $placeholders[$nextIndex] ?? null;
}
Demo: https://3v4l.org/JDKOH
So I have a Post which has Comments -- I'm trying to get the Comment # position within that post. For example, a Post has 15 comments, I want to be able to get the numerical position (i.e 1 (first post), 2 (second post), 3 (third post), etc, etc), and put this into a function somehow. That way when I can call $comment->position() and it will show as the 4th, 5th, whatever position in it is in.
I've done some searching around the web and couldn't find a solution. Any help is greatly appreciated! This is what I have so far:
public function position($id,$arr)
{
$total = $this->post->comments->count();
$position = $this->pluck('post_id')->search($this->id) + 1;
return ceil($total / $position);
//$comments_per_page = 25;
//$pos = array_search($id,$arr);
//$pos = $pos+1;
//return ceil($pos/$comments_per_page);
}
You should first get all your comments as collection.
// all comments as collection
$comments = $this->post->comments;
Then you can search through the collection using the search function and inserting an id you want to search for ... or any other param you want.
$id = 2;
$commentIndex = $comments->search(function($comment) use ($id) {
return $comment->id === $id;
});
Trying to produce a bulleted list from text field in MySQL - I have the bullets in the DB field : I'm pulling data into the array $products, I need the string in array to be formatted as a bullet list in the products $Keyfindings2 results
<?php
/* This controller renders the category pages */
class CategoryController{
public function handleRequest(){
$cat = Category::find(array('id'=>$_GET['category']));
if(empty($cat)){
throw new Exception("There is no such category!");
}
// Fetch all the categories:
$categories = Category::find();
// Fetch all the products in this category:
$products = Product::find(array('category'=>$_GET['category']));
// $categories and $products are both arrays with objects
$Keyfindings2 = explode('•', $products);
echo "<ul style=\' list-style-type:upper-roman;\'>\n";
foreach( $Keyfindings2 as $item )
{
echo "<li>$item</li><br />\n";
}
echo "</ul>";
render('category',array(
'title' => 'Browsing '.$cat[0]->name,
'categories' => $categories,
'products' => $Keyfindings2
));
}
}
?>
UPDATE: now getting 'undefined variable' in other part of code on line 1:
<li <?php echo ($active == $category->id ? 'data-theme="a"' : '') ?>>
<a href="?category=<?php echo $category->id?>" data-transition="fade">
<?php echo $category->name ?>
<span class="ui-li-count"><?php echo $category->contains?></span></a>
</li>
You problem is quite simple: you are using explode on the wrong thing.
If your code/comments is right $products is an array and you explode it. You probably have your PHP error level too low because this produce a PHP warning: PHP Warning: explode() expects parameter 2 to be string, array given in php shell code on line 1
So from there 2 solutions: either $products is an array of strings and you can do
function myExplode($product) {
return explode('•', $product);
}
$Keyfindings2 = array_map('myExplode', $products);
or $products is an array of objects (as your code comment suggests) and you go with:
function myExplode($product) {
// well actual the name of the field or method to call really depends on your
// code and there is no way we can tell it with what we have on your post
// so consider this an example
return explode('•', $product->productFieldContainingList);
}
$Keyfindings2 = array_map('myExplode', $products);
With either solution the goal is the same: to apply explode on the correct data, not on an array containing that data.
I need to gather all of the available attributes for the given product and then create a multidimensional array with them. Hopefully you can create a multidimensional array with more than two dimensions? The resulting array declarations should look like this:
$simpleArray[$child->getVendor()][$child->getColor()]=$child->getPrice();
First I'm gathering all the attributes then adding them to a string where I can call each one later:
$_product = $this->getProduct();
$_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes());
//Gather all attribute labels for given product
foreach($_attributes as $_attribute){
$attributeString .= '[$child -> get' . ucfirst($_attribute->getLabel()) . '()]';
}
Then I'm attempting to append that string to the array to declare it:
foreach($childProducts as $child) { //cycle through simple products to find applicable
//CAITLIN you are going to need way to search for other attributes, GET list of attributes
$simpleArray. $attributeString =$child->getPrice();
}
Mage::log('The attributeString is '. $simpleArray. $attributeString, null, 'caitlin.log'); //This is logging as "The attributeString is Array74"
Any suggestions?
You'll need to use recursion to do what you're requesting without knowing the attribute names while writing the code.
This will loop through and provide all of the child product prices, in a multi dimensional array based on the configurable attributes. It assumes that $_product is the current product.
$attrs = $_product->getTypeInstance(true)->getConfigurableAttributesAsArray($_product);
$map = array();
foreach($attrs as $attr) {
$map[] = $attr['attribute_code'];
}
$childPricing = array();
$childProducts = $_product->getTypeInstance()->getUsedProducts();
foreach($childProducts as $_child) {
// not all of the child's attributes are accessible, unless we properly load the full product
$_child = Mage::getModel('catalog/product')->load($_child->getId());
$topLevel = array($child->getData($map[sizeof($map)]) => $_child->getPrice());
array_pop($map);
$childProducts = array_merge($childProducts,$this->workThroughAttrMap($map,$_child,$topLevel));
}
//print_r childProducts to test, later do whatever you were originally planning with it.
In the same controller include this:
protected function workThroughAttrMap(&$map,$child,$topLevel) {
$topLevel = array($child->getData($map[sizeof($map)]) => $topLevel);
array_pop($map);
if(sizeof($map) > 0) return workThroughAttrMap($map,$child,$topLevel);
else return $topLevel;
}
I haven't tested this code so there may be a few minor bugs.
There are a few things you could do to make the code a bit cleaner, such as moving the first $topLevel code into the function, making that an optional parameter and initializing it with the price when it doesn't exist. I also haven't included any error checking (if the product isn't configurable, the child product doesn't have its price set, etc).
I am pulling my hair out here, I simply cannot get this to work.
I need to do a foreach loop to get all authors in a website, I then need to filter the ones with 0 published articles out and then echo the authors with articles into a UL LI with a special tag for the last author in the array:
My code at the moment has two functions, one to prefilter all authors that have at least one article and then in the second function count the number of authors left in the filtered array to then give the last entry in the array a special li tag. Code so far:
/*********************
Echo Filtered List
*********************/
function filtered_list() {
$authors = get_users('orderby=nicename');
$all_authors = array();
if ( count_user_posts( $author->id ) >= 1 ) {
return true;
}
}
function contributors() {
$i = 0;
filtered_list();
$len = count($all_authors);
foreach ($all_authors as $author ) {
if ( count_user_posts( $author->id ) >= 1 ) {
if ($i == $len - 1) {
echo "<li class='author-last clearfix'>";}
else {
echo "<li class='author clearfix'>";}
$i++;
If you read through your code you would probably see why it doesn't work.
First: Scopes
Read about variable scopes in the PHP manual. Basically, a variable declared inside a function is only available inside that function, so $all_authors is null inside contributors() as it has never been initialized.
The filtered_list function should return a filtered list of authors, so you should loop, though $authors and add the author to $all_authors if, and only if she has 1 or more posts. After the loop, return the array.
Now you can get the filtered list by setting the return value of the fist function to the $all_authors in contributors (or better yet, just call them $authors).
Now you are ready to iterate over the list of authors and find their post. To do this, you need two loops. One for authors, and one for the posts.
foreach author in authors
foreach post in author->posts
if post is last post
print special stuff
else
print normal stuff
endif
endforeach
endforeach
Hope this helps, and that you'll learn something from it. Point is: Read though your code line by line and explain to yourself what it does.