Loop through fields and generate comma separated list

I have a bunch of text fields for capturing various social media profile address and handles. I need to run these out as a comma seperated list of values in a JSON block.

There are two common things about the field names if it helps. The are prefixed with ‘social’" and suffixed with either “url” or “handle” like this:

Socialtwitterurl: https://twitter.com
Socialtwitterhandle: @HashandSalt

I want the values of all fields that don’t contain handle, and then run them out into the SameAs field in the json block.

<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "LocalBusiness",
...
},
"sameAs" : [ "http://www.facebook.com/example",
"http://www.twitter.com/example",
"http://plus.google.com/example"]
}
...
</script>

I know someone might say use a structure field but i dont want to and it will cause reworking a bunch of other stuff.

Any ideas?

Of course:

<?php
$fields = $page->content()->fields();
function getSocialFields($value) {
  return strpos($value, 'social') === 0 && substr($value, -6)  !== 'handle';
}
$result = array_filter($fields, 'getSocialFields');
dump($result);
echo implode(',',$result);

brilliant…almost… but that gives me the keys, not the values. Am i missing something?

<?php

$fields = $site->content()->fields();
function getSocialFields($value) {
  return strpos($value, 'social') === 0 && substr($value, -6)  !== 'handle';
}
$result = array_filter($fields, 'getSocialFields');
$profiles = implode(',',$result);
?>

<?= $profiles ?>

Result:

socialtwitterurl,socialinstagramurl,sociallinkedinurl,socialfacebookurl,socialpinteresturl,socialyoutubeurl,socialgoogleplusurl

Also how would I wrap each one in double qoutes?

Well, if you have the fields, you can loop through them…

$socialValues = [];
foreach($result as $field) {
  $socialValues[] = $page->{$field}()->value();
}

Ah ha! I missed a bit… it does work:

<?php

$fields = $site->content()->fields();
function getSocialFields($value) {
  return strpos($value, 'social') === 0 && substr($value, -6)  !== 'handle';
}
$result = array_filter($fields, 'getSocialFields');

var_dump($result);

$profiles = implode(', ',$result);

$socialValues = [];
foreach($result as $field) {
  $socialValues[] = $site->{$field}()->value();

}

var_dump($socialValues);

?>

As I said, you then have to loop through the fields and get the values.

Or, you do the following:

dump($page->content()->toArray('fields')); 

and then filter by keys…

$content = $page->content()->toArray('fields');
function getSocialFields($value) {
  return strpos($value, 'social') === 0 && substr($value, -6)  !== 'handle';
}
$result = array_filter($content, 'getSocialFields',ARRAY_FILTER_USE_KEY);

Sorted, this works:

<?php
$fields = $site->content()->fields();
function getSocialFields($value) {
  return strpos($value, 'social') === 0 && substr($value, -6)  !== 'handle';
}
$result = array_filter($fields, 'getSocialFields');
$socialValues = [];
foreach($result as $field) {
  $socialValues[] = $site->{$field}()->value();
}
//var_dump($socialValues);
$profilelist = '"'.implode('","', $socialValues).'"';
?>

<?= $profilelist ?>

Thanks @texnixe

Slight tweak to exclude empty fields:

<?php
$fields = $site->content()->fields();
function getSocialFields($value) {
  return strpos($value, 'social') === 0 && substr($value, -6)  !== 'handle';
}
$result = array_filter($fields, 'getSocialFields');
$socialValues = [];
foreach($result as $field) {
  if($site->{$field}()->isNotEmpty()) {
    $socialValues[] = $site->{$field}()->value();
  }
}
//var_dump($socialValues);
$profilelist = '"'.implode('","', $socialValues).'"';
?>

<?= $profilelist ?>

Less code:

$fields = $page->content()->toArray('fields');

function getSocialFields($value, $key) {
  return strpos($key, 'social') === 0 && substr($key, -6)  !== 'handle' && $value !== '';
}
$socialValues = array_filter($fields, 'getSocialFields',ARRAY_FILTER_USE_BOTH);

echo implode(',', array_map(function($value) {
  return '"' . $value . '"';
}, $socialValues));

Lovely, thanks @texnixe

Ended up with this:

<?php
$fields = $site->content()->toArray('fields');

function getSocialFields($value, $key) {
  return strpos($key, 'social') === 0 && substr($key, -6)  !== 'handle' && $value !== '';
}
$socialValues = array_filter($fields, 'getSocialFields',ARRAY_FILTER_USE_BOTH);

$profilelist = implode(',', array_map(function($value) {
  return '"' . $value . '"';
}, $socialValues));

?>

<?= $profilelist ?>

:peace_symbol:

Ok now theres a problem. I need to use this in more than one snippet, and you can’t redeclare functions.

How do i move it to a controller so it works everywhere?

Just move it to a controller and pass the variable down to the template.

Sorted. It wasn’t quite as clear cut as that because im using shared controllers. Works now though :slight_smile:

I just moved this onto my live server and it threw a whoops, the problem is this line

  $socialValues = array_filter($fields, 'getSocialFields',ARRAY_FILTER_USE_BOTH);

Error:

array_filter() expects at most 2 parameters, 3 given

Works fine on my local server with PHP (PHP 7.1.12) but the server is running PHP 7.0. Is that the problem?

Yup. That was the problem. Upgraded server to 7.2 and all is well.

The third (flag) parameter was added in PHP 5.6, so that error is a bit weird to appear in PHP 7.0 unless it was some sort of bug or a misconfiguration on your server.

http://php.net/manual/de/function.array-filter.php

That’s weird then. It’s a CentOs 7 VPS running WHM & cPanel. I use Easy Apache 4 WHM extension to install PHP stuff. As far as I can tell all sites on the VPS inherit the system default PHP (which i think is 5.4) unless told otherwise, but that domain was set to use PHP 7.0 so it should not have been an issue.

i think it uses a php.ini file in the domain root to set custom php verision (and any other settings that differ from the global php.ini). Maybe it got narfed when I ran rSync so it fell back to the system defualt until i reset in cPanel.

Strange.