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..."]

4 ответа

Решение

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']

Проблемы:

Шорткоды 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.

Простой способ использую:

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

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

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

У меня есть альтернативный способ сделать это в$contentвместо этого короткого кода.

Это решение повышает читаемость/связность ваших данных. Но это может быть не лучший способ, если вы хотите использовать $content и для других целей.

используемый короткий код похож на...

      // in wordpress editor or your *.php file

[testimonial_carousel_list]
[
  {
    "message": "Lorem ipsum dolor sit amet.",
    "avatar": "https://via.placeholder.com/150",
    "full_name": "John Doe"
  },
  {
    "message": "Vivamus vel ornare purus, in faucibus tellus.",
    "avatar": "https://via.placeholder.com/150",
    "full_name": "Jane Smith"
  },
  {
    "message": "Morbi tristique augue vel mi ornare, sit amet viverra lectus semper.",
    "avatar": "https://via.placeholder.com/150",
    "full_name": "David Lee"
  }
]
[/testimonial_carousel_list]

И вот как с этим справиться: введите функцию шорткода.

      // it might be in functions.php of your theme

function testimonial_carousel_list_shortcode($_atts, $content = null) {
  $items = json_decode($content);

  // ...rest of your code whatever you what to do with array $items
}
add_shortcode('testimonial_carousel_list', 'testimonial_carousel_list_shortcode');

// this is required if you want to json_decode() on your $content.
// because wptexturize will change your `'` or `"` to `‘` or `“` it will made json_decode got error.
function shortcodes_to_exempt_from_wptexturize( $shortcodes ) {
    $shortcodes[] = 'testimonial_carousel_list';
    return $shortcodes;
}
add_filter('no_texturize_shortcodes', 'shortcodes_to_exempt_from_wptexturize');
Другие вопросы по тегам