Штрих-коды Wordpress передают массив значений

Я создаю несколько коротких кодов WordPress, предназначенных для обеспечения внутренней навигации на странице (одна страница с большим количеством разделов контента и ее собственное меню).

Это то, что у меня есть:

//menu
function internal_menu($atts) {
  extract(shortcode_atts(array(
   'href1' => '#jl1',
   'href2' => '#jl2',
   'href3' => '#jl3',
   'href4' => '#jl4',
  ), $atts));
  return '<div id="internalPageMenu">
    <ul>
        <li><a href="' . $href1 . '"><i class="fa fa-bars"></i>link 1</a></li>
        <li><a href="' . $href2 . '">link 2</a></li>
        <li><a href="' . $href3 . '">link 3</a></li>
        <li><a href="' . $href4 . '">link 4</a></li>
    </ul>
    </div>';
}
add_shortcode('internal-menu', 'internal_menu');

//menu target
function internal_menu_target($atts) {
  extract(shortcode_atts(array(
   'id' => 'jl1',
   'text' => '',
   ), $atts));
   return '<h3 id="' . $id . '">' . $text . '</h3>';
}
add_shortcode('internal-menu-target', 'internal_menu_target');

И используя это в моей панели администратора Wordpress:

[internal-menu]
[internal-menu-target id="jl1"]
Some content
[internal-menu-target id="jl2"]
...etc...

Как сделать динамическое меню (не ограниченное количеством элементов, которое оно может иметь)? Например, короткий код:

[internal-menu targets="jl1, jl2, jl3, jl4, jl5, ...etc..."]

Ответ 1

foreach будет вашим ответом здесь. По моему мнению, это будет самым простым и чистым. Прежде чем я приведу вам пример кода, проанализируйте свой код и просмотрите все свои недостатки и как мы их исправим.

НЕДОСТАТКИ

  • Никогда не используйте extract(). exctract() создает переменные "на лету", что является проблематичным. Вы не можете должным образом отлаживать extract() (если вы даже можете), поэтому, когда он терпит неудачу, вы действительно имеете свою работу, вырезанную для вас, без необходимости. По этим причинам он был полностью удален из ядра и кода. См. билет на трафик 22400. У вас должен быть злой список с query_posts и extract() в двух верхних позициях, что я знаю, насколько плохи эти два.

  • Вы не дезинфицируете и не проверяете входные данные, которые могут привести к тому, что хакер вводит jquery в ваш код, чтобы взломать ваш сайт. Никогда не доверяйте никаким данным, которые поступают со стороны пользователя и URL-адреса, он может быть заражен.

  • Как вы уже знаете, взятые из вашего кода, короткие коды не могут не содержать значения массива, значения должны быть строковыми. В вашем случае нам нужно создать массив из строковых значений. Опять же, поскольку вы не можете доверять пользователю не использовать пробелы до запятых или после них, разумно и рекомендуется удалять все пробелы, если они есть, для того, чтобы ваша функция explode правильно создала ваш массив

  • С помощью этого нового подхода вы должны убедиться, что ваши значения в ваших строках находятся в правильном порядке и что строки являются правильной длиной. Если нет, вы получите неожиданный вывод

Давайте рассмотрим первый короткий код: ( ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ:. Все приведенные ниже коды непроверены. Возможно, они ошибочны или имеют синтаксические ошибки)

internal-menu

//menu
function internal_menu( $atts ) 
{
    $attributes = shortcode_atts(
        array(
           'href' => '',
         ), 
        $atts
    );

    $output = '',
    // Check if href has a value before we continue to eliminate bugs
    if ( !$attribute['href'] )
        return $output;
    // Create our array of values
    // First, sanitize the data and remove white spaces
    $no_whitespaces = preg_replace( '/\s*,\s*/', ',', filter_var( $attributes['href'], FILTER_SANITIZE_STRING ) ); 
    $href_array = explode( ',', $no_whitespaces );

    $output .= '<div id="internalPageMenu">';
        $output .= '<ul>';

            foreach ( $href_array as $k => $v ) { 
                // From your code, link 1 is different, so I kept it as is
                if ( $k == 0 ) {
                    $output .= '<li><a href="#' . $v . '"><i class="fa fa-bars"></i>link 1</a></li>';
                } else { 
                    $output .= '<li><a href="#' . $v . '">link ' . ($k + 1 ) . '</a></li>';
                }
            }

        $output .= '</ul>';
    $output .= '</div>';

    return $output;
}
add_shortcode( 'internal-menu', 'internal_menu' );

Затем вы можете использовать короткий код, как показано ниже.

[internal-menu href='jl1, jl2, jl3, jl4']

internal-menu-target

//menu target
function internal_menu_target($atts) 
{
    $attributes = shortcode_atts(
        array(
           'id' => '',
           'text' => '',
         ), 
        $atts
    );

    $output = '',
    // Check if href has a value before we continue to eliminate bugs
    if ( !$attribute['id'] || !$attribute['text'] )
        return $output;

    // Create our array of values
    // First, sanitize the data and remove white spaces
    $no_whitespaces_ids = preg_replace( '/\s*,\s*/', ',', filter_var( $attributes['id'], FILTER_SANITIZE_STRING ) ); 
    $ids_array = explode( ',', $no_whitespaces_ids );

    $no_whitespaces_text = preg_replace( '/\s*,\s*/', ',', filter_var( $attributes['text'], FILTER_SANITIZE_STRING ) ); 
    $text_array = explode( ',', $no_whitespaces_text );

    // We need to make sure that our two arrays are exactly the same lenght before we continue
    if ( count( $ids_array ) != count( $text_array ) )
        return $output;

    // We now need to combine the two arrays, ids will be keys and text will be value in our new arrays
    $combined_array = array_combine( $ids_array, $text_array );
    foreach ( $combined_array as $k => $v )
        $output .= '<h3 id="' . $k . '">' . $v . '</h3>';

    return $output;
}
add_shortcode('internal-menu-target', 'internal_menu_target');

Вы можете использовать этот короткий код следующим образом:

[internal-menu-target id='1,2,3,4' text='text 1, text 2, text 3, text 4']

Ответ 2

Проблемы:

Шорткоды Wordpress имеют некоторые болезненные ограничения в формате данных, которые могут быть переданы...

Переменные, разделенные пробелом:

[shortcode a="1 2"]

результат: $atts=['a'='"1', 0='2"']

']' закрывает шорткод:

[shortcode b=[yay]]

результат: $atts=['b'='[yay']

Решение:

Вы можете обойти это, используя urlencode():

[shortcode atts=a=1+2&b=%5Byay%5D]

разобрать это так:

parse_string($atts['atts'],$atts);

результат: $atts=['a'=>'1 2', b=>'[yay]']

Это даст вам массив, который вы хотите передать.

Теперь что касается построения вашего меню (ов):

function internal_menu($atts) {
  // allow passing + and ] in the text of the links:
  parse_string($atts["links"],$links);

  // the defaults, verbatim from the question:
  if (!count($links)) $links=[
    'href1' => '#jl1',
    'href2' => '#jl2',
    'href3' => '#jl3',
    'href4' => '#jl4',
  ];

  foreach ($links as $text=>$href) $ul=."<li><a href=\"$href\">$text</a></li>";

  return '<div id="internalPageMenu"><ul>'.$ul.'</ul></div>';
}

add_shortcode('internal-menu', 'internal_menu');

//menu target

function internal_menu_target($atts) {
  // allow passing + and ] in the text:
  if (@$atts[text]) $atts['text']) = urldecode($atts['text']);

  // the defaults, verbatim from the question:
  $atts=array($atts)+['text'=>'','id'=>'jl1'];

  return '<h3 id="' . $link['id'] . '">' . $link['text'] . '</h3>';
}

add_shortcode('internal-menu-target', 'internal_menu_target');

а потом корми его так:

[internal-menu links=First+Link=#jl1&Second+Link=#jl2&Google=https://google.com]

[internal-menu-target text=Section+1 id=jl1]

и т.п.

Кстати, extract() прекрасно, если вы используете его ответственно:

/* concatenates 3 words of wisdom into a polite policy direction
 *
 * @param $attr: hash of function args
 *          foo = the first word (Kindly)
 *          bar = the second word (ignore)
 *          baz = the third word (totalitarians)
 */

function excellent_policy($attr){
  $defaults=['foo'=>'Kindly', 'bar'=>'ignore', 'baz'=>'totalitarians'];
  extract((array)array_intersect_key($attr,$defaults)+$defaults);
  echo "$foo $bar $baz!";
}

Это импортирует $ foo, $ bar и $ baz из $ attr в локальную область видимости в удобочитаемом и предсказуемом виде, предоставляет значения по умолчанию для этих переменных, если они не были переданы, и предотвращает создание любых непредвиденных переменных.

Есть хорошие и плохие способы использования языковых функций. Запретить всем использование языковой функции, потому что кто-то может ее использовать плохо, все равно, что запретить всем дышать, потому что кто-то может попытаться вдохнуть Jello.

Ответ 3

Простой способ использования:

[my param="key1=value1&key2=value2"]

в обратном вызове с коротким кодом просто выполните:

parse_str( str_replace("&amp;", "&", $attrs['param']), $array);
// var_dump( $array );