Whats the best method to create this list with PHP? - php

I'm new to the world of PHP and looking to see if there is a better way of writing this little code snippet that I have. Basically, it gives variables for some social media links, checks if they are empty, creates an array in a function and I call the array in a UL. I know its simple but I'm just looking if what I have is best or if I can improve on it any.
<?php
$facebook = of_get_option('facebook');
$twitter = of_get_option('twitter');
$youtube = of_get_option('youtube');
$linkedIn = of_get_option('linkedin');
$instagram = of_get_option('instagram');
$socialMediaLinks = array(
);
if (!empty($facebook)){
$socialMediaLinks[facebook] = $facebook;
}
if (!empty($twitter)){
$socialMediaLinks[twitter] = $twitter;
}
if (!empty($youtube)){
$socialMediaLinks[youtube] = $youtube;
}
if (!empty($linkedIn)){
$socialMediaLinks[linkedIn] = $linkedIn;
}
if (!empty($instagram)){
$socialMediaLinks[instagram] = $instagram;
}
function socialMediaList($value, $key){
echo '<li class="'.$key.'">'.$key.'</li>';
}
?>
<?php if (!empty($socialMediaLinks)){ ?>
<ul class="social-media">
<?php array_walk($socialMediaLinks, 'socialMediaList'); ?>
</ul>
<?php } ?>

You could shorten the code by simply doing:
$socialMediaLinks = array_filter(array(
'facebook' => of_get_option('facebook'),
'twitter' => of_get_option('twitter'),
'youtube' => of_get_option('youtube'),
'linkedIn' => of_get_option('linkedIn'),
'instagram' => of_get_option('instagram'),
));
This will automatically remove all empty entries, so you won't need that whole bunch of if-statements afterwards.

Try this:
<?php
$socialMediaItems = array(
'facebook' => of_get_option('facebook'),
'twitter' => of_get_option('twitter'),
'youtube' => of_get_option('youtube'),
'linkedin' => of_get_option('linkedin'),
'instagram' => of_get_option('instagram')
);
$socialMediaLinks = array();
foreach ($socialMediaItems as $key => $item) {
if ($item) {
$socialMediaLinks[$key] = $item;
}
}
function socialMediaList($value, $key){
echo '<li class="'.$key.'">'.$key.'</li>';
}
?>
<?php if (!empty($socialMediaLinks)){ ?>
<ul class="social-media">
<?php array_walk($socialMediaLinks, 'socialMediaList'); ?>
</ul>
<?php } ?>

Using array
<?php
$facebook = of_get_option('facebook');
$twitter = of_get_option('twitter');
$youtube = of_get_option('youtube');
$linkedIn = of_get_option('linkedin');
$instagram = of_get_option('instagram');
$socialMediaLinks = array();
$madeArray = array('facebook' => $facebook,'twitter' => $twitter,'youtube' => $youtube,'linkedin' => $linkedIn,'instagram' => $instagram);
foreach ($madeArray as $key => $value) {
if (!empty($value)) {
$socialMediaLinks[$key] = $value;
}
}
function socialMediaList($value, $key){
echo '<li class="'.$key.'">'.$key.'</li>';
}
?>
<?php if (!empty($socialMediaLinks)){ ?>
<ul class="social-media">
<?php array_walk($socialMediaLinks, 'socialMediaList'); ?>
</ul>
<?php } ?>

Better can be:
<?php
$socialmedia = array('facebook', 'twitter', 'youtube', 'linkedin' 'instagram');
$socialMediaLinks = array();
function GetOptions($name)
{
$value = of_get_option($name);
if (!empty($value))
$socialMediaLinks[$name] = $value;
}
foreach ($socialmedia as $smname)
GetOptions($smname);
function socialMediaList($value, $key){
echo '<li class="'.$key.'">'.$key.'</li>';
}
if (!empty($socialMediaLinks)){
?>
<ul class="social-media">
<?php array_walk($socialMediaLinks, 'socialMediaList'); ?>
</ul>
<?php
}
?>

I'd made something like this:
$social_networks = ['facebook', 'twitter', 'youtube', 'linkedin', 'instagram'];
$media_links = [];
foreach ($social_networks as $network) {
if ($option = of_get_option($network)) {
$media_links[$network] = $option;
}
}
// your code to output...
If you write simple application with short support time - your displaying style its normal. But if it something complex, you should look to MVC pattern.

Related

PHP MVC FOREACH display

i struggling with forloop in MVC.
i want to pass data from input text where in data is equivalent to 1,2,3,4,5,6,7...... -that is from database.
i pass it to controller and get the data using $_POST method with name text1.
here is my controller code
{
$template = $this->loadView('view_display');
if(isset($_POST['check'])):
$text1= $_POST['text1'];
$text1= explode(',', $text1);
foreach($text1 as $text1):
$rem = $this->Faculty_model->testFunction($this->security_plugin->cleanInput($text1));
$template->set(['stud' => $rem, 'username' => $this->session_helper->get('username'), 'security'=> $this->security_plugin, 'url' => $this->url_helper]);
endforeach;
endif;
$this->security_plugin->CSRFToken();
$template->render();
here is my model
{
$sql="select * from table where id=:text1";
$bind = array(
':text1' => $text1
);
$data = $this->db->fetchAll($sql, $bind);
return $data;
}
and this is my view
<?php if(!empty($stud)): ?>
<?php foreach($stud as $stud): ?>
<?php echo $security->SanitizeString($stud->ID); ?>
<?php echo $security->SanitizeString($stud->NAME); ?>
<?php echo $security->SanitizeString($stud->AGE); ?>
The problem is it will only display the last number from text1 textbox. i cant figure it out.
anyhelp is appreciated :)
1.You need to define $rem as an array before foreach() and then do assignment of values.
2.Put $template->set() code outside of foreach()
$template = $this->loadView('view_display');
if(isset($_POST['check'])):
$text1= $_POST['text1'];
$text1= explode(',', $text1);
$rem = [];
foreach($text1 as $text1):
$rem[] = $this->Faculty_model->testFunction($this->security_plugin->cleanInput($text1));
endforeach;
$template->set(['stud' => $rem, 'username' => $this->session_helper->get('username'), 'security'=> $this->security_plugin, 'url' => $this->url_helper]);
endif;
$this->security_plugin->CSRFToken();
$template->render();

PHP - creating a new array through nested arrays while creating a post/image relationship

PHP 7.2
Wordpress 4.9.8
Advanced Custom Fields 5.7.7
I'm interested in creating an array where each item would hold:
post id
post title
array of images belonging to post
I am using an ACF repeater for every post that holds many images, the repeater name is carousel.
There is no connection between the WP post object and the ACF fields.
The issue:
nested foreach pushes all the images into the first post.
Expected:
nested foreach will fill the $randomArray only with images that belong to that post ID.
$workshop_posts_args = array(
'post_type' => 'workshops'
);
$randomArray = [
'post_id' => '',
'post_title' => '',
'post_image_url' => []
];
$post_query = new WP_Query($workshop_posts_args);
if ($post_query->have_posts()) {
while ($post_query->have_posts()) {
$post_query->the_post();
$carousel_array = get_field('carousel', get_the_ID());
echo "<h2>".get_the_title()."</h2>";
if ($carousel_array) {
foreach ($carousel_array as $carousel_images) {
foreach ($carousel_images as $image) {
$randomArray['post_id'] = get_the_ID();
$randomArray['post_title'] = get_the_title();
$randomArray['post_image_url'][] = $image['url'];
echo 'image_url:'.$image['url'].'<br>The array: <pre>'.print_r($randomArray, true).'</pre>';
?>
<?php
}
}
}
}
}
?>
<h1>TOTAL ARRAY</h1>
<pre><?php print_r($randomArray) ?></pre>
You are over-writing array index again and again inside loop and that's you problem.
so do:-
$randomArray = []; //before post_query
And change if block like below:-
if ($post_query->have_posts()) {
while ($post_query->have_posts()) {
$post_query->the_post();
$id = get_the_ID();
$randomArray[$id]['post_id'] = $id;
$randomArray[$id]['post_title'] = get_the_title();
$carousel_array = get_field('carousel', $id);
if ($carousel_array) {
foreach ($carousel_array as $carousel_images) {
foreach ($carousel_images as $image) {
$randomArray[$id]['post_image_url'][] = $image['url'];
?>
<?php
}
}
}
}
}
Note:- rest code will be same
the above code will give you post-id based multi-dimensional array. if you want indexes to be 0,1,2,3..... format then do:-
$randomArray = array_values($randomArray);
Use proper indexing of $randomArray like below:
<?php
$workshop_posts_args = array(
'post_type' => 'workshops'
);
$randomArray = array();
$post_query = new WP_Query($workshop_posts_args);
$index = 0;
if ($post_query->have_posts()) {
while ($post_query->have_posts()) {
$post_query->the_post();
$randomArray[$index]['post_id'] = get_the_ID();
$randomArray[$index]['post_title'] = get_the_title();
$carousel_array = get_field('carousel', get_the_ID());
//echo "<h2>".get_the_title()."</h2>";
if ($carousel_array) {
foreach ($carousel_array as $carousel_images) {
foreach ($carousel_images as $image) {
$randomArray[$index]['post_image_url'][] = $image['url'];
//echo 'image_url:'.$image['url'].'<br>The array: <pre>'.print_r($randomArray, true).'</pre>';
?>
<?php
}
}
}
$index++;
}
}
?>
<h1>TOTAL ARRAY</h1>
<pre><?php print_r($randomArray) ?></pre>

Count images from dirs and show less on top

I am using this code to display the total files in different directories, all good but for example cats=50 then dogs=30 and fish=10. how can I make something so that I get fish on top then dogs and finally cats..
function scan_dir($path){
$ite=new RecursiveDirectoryIterator($path);
$nbfiles=0;
foreach (new RecursiveIteratorIterator($ite) as $filename=>$cur) {
$nbfiles++;
}
if($nbfiles > 2) $nbfiles = $nbfiles - 2;
return $nbfiles;
}
$dogs = scan_dir('/home/dogs/');
$cats = scan_dir('/home/cats/');
$fish = scan_dir('/home/fish/');
<table border="1">
<tr><td><b>Animal</b></></></td><td><b>Total Files</b></></></td></tr>
<tr><td>Dogs</td><td><?=$dogs?></td></tr>
<tr><td>Cats</td><td><?=$cats?></td></tr>
<tr><td>Fish</td><td><?=$fish?></td></tr>
</table>
Quick and dirty:
$dogs = scan_dir('/home/dogs/');
$cats = scan_dir('/home/cats/');
$fish = scan_dir('/home/fish/');
$arr = array("Dogs" => $dogs, "Cats" => $cats, "Fish" => $fish);
asort($arr);
echo '<table border="1">';
echo "<tr><td><b>Animal</b></></></td><td><b>Total Files</b></></></td></tr>";
foreach ($arr as $key=>$value) {
echo "<tr><td>$key</td><td>$value</td></tr>";
}
echo "</table>";
With a working example.
$array = array($dogs => 'dogs', $cats => 'cats', $fish => 'fish');
ksort($array); //sorts array the way you want
This should work.
<?php
function scan_dir($path){
$count = 0;
$it = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
foreach (new RecursiveIteratorIterator($it) as $dummy) {
++$count;
}
return $count;
}
$animals = array(
'Dogs' => '/home/dogs/',
'Cats' => '/home/cats/',
'Fish' => '/home/fish/',
);
foreach ($animals as $animal => $path) {
$animals[$animal] = scan_dir($path);
}
arsort($animals);
?>
<table border="1">
<tr><td><b>Animal</b></td><td><b>Total Files</b></td></tr>
<?php foreach ($animals as $animal => $count): ?>
<tr><td><?=$animal?></td><td><?=$count?></td></tr>
<?php endforeach; ?>
</table>

Nested lists using PHP's iterator?

I'm trying to display this kind of array:
$nodes = array(
1 => array(
'title' => 'NodeLvl1',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl1',
'children' => array(
1 => array(
'title' => 'NodeLvl2',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl2',
'children' => array(
1 => array(
'title' => 'NodeLvl3',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl3',
'children' => array(),
),
),
),
),
),
3 => array(
'title' => 'NodeLvl1',
'children' => array(),
),
);
like this:
<ul>
<li>
NodeLvl1
</li>
<li>
NodeLvl1
<ul>
<li>NodeLv2</li>
...
</ul>
</li>
...
Basically a nested list taking into account the "children" property. So far I've come up with this:
class It extends RecursiveIteratorIterator{
protected
$tab = "\t";
public function beginChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
}
public function endChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."\n</ul>";
}
public function nextElement(){
echo str_repeat($this->tab, $this->getDepth() + 1).'<li>';
}
}
$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
echo $item;
Which doesn't work quite right: I get each item wrapped between <ul>s and I don't know how can I close <li>s...
Any ideas on how to make this work? Also is it possible to get all the array properties (the actual element), instead of just the "title" property inside my foreach() loop? And can this be done with objects instead of arrays?
Do you need a class iterator for this? You could do this with just a simple function...
function arrayToListHTML($array, $level = 0) {
static $tab = "\t";
if (empty($array)) return;
$tabs = str_repeat($tab, $level * 2);
$result = "{$tabs}<ul>\n";
foreach ($array as $i => $node):
$result .= "{$tabs}{$tab}<li>\n{$tabs}{$tab}{$tab}{$node['title']}\n".arrayToListHTML($node['children'], $level + 1)."{$tabs}{$tab}</li>\n";
endforeach;
$result .= "{$tabs}</ul>\n";
return $result;
}
Which will produce this output:
<ul>
<li>
NodeLvl1
</li>
<li>
NodeLvl1
<ul>
<li>
NodeLvl2
</li>
<li>
NodeLvl2
<ul>
<li>
NodeLvl3
</li>
<li>
NodeLvl3
</li>
</ul>
</li>
</ul>
</li>
<li>
NodeLvl1
</li>
</ul>
This covers what you've shown us, but I'm not sure what you mean by other properties. Are there more properties in each array other than title and children?
Instead of trying to use your class like an array in foreach() consider using your class to perform the function. For instance, the following code will output correctly but the function is performed inside the class.
class It extends RecursiveIteratorIterator{
protected
$tab = "\t";
public function beginChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
}
public function endChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth)."\n</ul>";
}
public function nextElement(){
echo str_repeat($this->tab, $this->getDepth())."<li>".$this->current()."</li>\n";
}
}
$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
//echo $item;
//it will be better to write a function inside your custom iterator class to handle iterations
?>
You can use RecursiveCachingIterator to do what you want. Here is an example, (source: https://github.com/cballou/PHP-SPL-Iterator-Interface-Examples/blob/master/recursive-caching-iterator.php)
<?php
// example navigation array
$nav = array(
'Home' => '/home',
'Fake' => array(
'Double Fake' => array(
'Nested Double Fake' => '/fake/double/nested',
'Doubly Nested Double Fake' => '/fake/double/doubly'
),
'Triple Fake' => '/fake/tripe'
),
'Products' => array(
'Product 1' => '/products/1',
'Product 2' => '/products/2',
'Product 3' => '/products/3',
'Nested Product' => array(
'Nested 1' => '/products/nested/1',
'Nested 2' => '/products/nested/2'
)
),
'Company' => '/company',
'Privacy Policy' => '/privacy-policy'
);
class NavBuilder extends RecursiveIteratorIterator {
// stores the previous depth
private $_depth = 0;
// stores the current iteration's depth
private $_curDepth = 0;
// store the iterator
protected $_it;
/**
* Constructor.
*
* #access public
* #param Traversable $it
* #param int $mode
* #param int $flags
*/
public function __construct(Traversable $it, $mode = RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
{
parent::__construct($it, $mode, $flags);
// store the caching iterator
$this->_it = $it;
}
/**
* Override the return values.
*
* #access public
*/
public function current()
{
// the return output string
$output = '';
// set the current depth
$this->_curDepth = parent::getDepth();
// store the difference in depths
$diff = abs($this->_curDepth - $this->_depth);
// get the name and url of the nav item
$name = parent::key();
$url = parent::current();
// close previous nested levels
if ($this->_curDepth < $this->_depth) {
$output .= str_repeat('</ul></li>', $diff);
}
// check if we have the last nav item
if ($this->hasNext()) {
$output .= '<li>' . $name . '';
} else {
$output .= '<li class="last">' . $name . '';
}
// either add a subnav or close the list item
if ($this->hasChildren()) {
$output .= '<ul>';
} else {
$output .= '</li>';
}
// cache the depth
$this->_depth = $this->_curDepth;
// return the output ( we could've also overridden current())
return $output;
}
}
?>
Usage
<?php
try {
// generate the recursive caching iterator
$it = new RecursiveCachingIterator(new RecursiveArrayIterator($nav));
// build the navigation with the iterator
$it = new NavBuilder($it, RecursiveIteratorIterator::SELF_FIRST);
// display the resulting navigation
echo '<ul id="nav">' . PHP_EOL;
foreach ($it as $value) {
echo $value . "\n";
}
echo '</ul>' . PHP_EOL;
} catch (Exception $e) {
var_dump($e); die;
}
?>
First let me explain few things to you. Your array has two pattens
One with numeric indexes
One with string indexes, with title and children which has be parsed differently
I think a recursive function plays very nice role on this part, rather than complex logics. And our recursive function has to be able to handle both patterns separately.
Here is my version of the function you could use with explanation
function arraytolist(Array $array) { //ensure what you receive is array
if(count($array)) { //only if it has some items
//In case the array has `title` index we encountered out PATTERN 2
if(isset($array['title'])) {
$o = "<li>";
$o .= $array['title']; //simply add the title
$o .= arraytolist($array['children']); //and pass the children to this function to verify again
$o .= "</li>";
} else { //if its a normal array, //PATTERN 1
$o = "<ul>";
foreach($array as $value) {
$n = "";
if(is_array($value)) { //in case its an array again,
//send it to this very same function so that it will return as output again
$n .= arraytolist($value);
} else {
$n .= "<li>$value</li>";
}
$o .= strlen($n) ? $n : ""; //if $n has something use it otherwise not
}
$o .= "</ul>"; //lets close the ul
}
return $o;
}
}
Some Advantage of this function
No iteration level
As long as its an array and has item, keeps on building them
Power of simple logic in PHP
I would opt for a simple recursive function that flattens the array into the text/html format:
function arrToList( $arr, $embedded = false ) {
$output = array();
if ( $embedded ) $output[] = '<li>';
$output[] = '<ul>';
foreach ( $arr as $key => $values ) {
$output[] = '<li>'.$values['title'].'</li>';
if ( $values['children'] ) {
$output[] = arrToList( $values['children'], true );
}
}
$output[] = '</ul>';
if ( $embedded ) $output[] = '</li>';
return implode(PHP_EOL, $output);
}
Output from using your input:
NodeLvl1
NodeLvl1
NodeLvl2
NodeLvl2
NodeLvl3
NodeLvl3
NodeLvl1
or the actual code:
<ul>
<li>NodeLvl1</li>
<li>NodeLvl1</li>
<li>
<ul>
<li>NodeLvl2</li>
<li>NodeLvl2</li>
<li>
<ul>
<li>NodeLvl3</li>
<li>NodeLvl3</li>
</ul>
</li>
</ul>
</li>
<li>NodeLvl1</li>
</ul>
Cheers

Codeigniter: how can I send a foreach statement to the view?

Controller:
$categorys = array(
'1234' => array('Car Audio','Car Subwoofers'),
'12' => array('Car Stereos')
)
$category_id = $this->input->get('category_id');
$product_id = $this->input->get('modelNumber');
if (array_key_exists($category_id,$categorys))
{
foreach($categorys[$category_id] as $key => $value)
{
echo $value;
}
}
How can I echo the $value outputted from the foreach statement in my view file?
You can pass the whole array to the view and run the foreach directly in the view, e.g.:
$data['array'] = array(/* etc. */);
$this->load->view('view', $data);
And in the view:
<?php foreach($array as $key => $value): ?>
<p>The key is <?php echo $key; ?><br>
The value is <?php echo $value; ?></p>
<?php endforeach; ?>
Controller
if (array_key_exists($category_id,$categorys))
{
$query['cats'] = $categorys[$category_id];
}
View
foreach($cats as $key => $value)
{
echo $value;
}

Categories