Save / Show multi line text in metabox

Why ?

You are using sanitize_text_field() in the metabox save function. According to the code referensece it,

  • Checks for invalid UTF-8,
  • Converts single < characters to entities
  • Strips all tags
  • Removes line breaks, tabs, and extra whitespace
  • Strips octets

When saving textarea you want to use sanitize_textarea_field() instead.

The function is like sanitize_text_field(), but preserves new lines
(\n) and other whitespace, which are legitimate input in textarea
elements.

UPDATE

For fixing the output, you could do something like this. The key part here is str_replace(), which is used to replace the different types of linebreaks with <br> tags. If you want to have p tags also, you could consider using wpautop() instead.

Please don’t mind that I took the liberty to format the output handling a bit.

if ( ! $the_query->posts ) {
  return sprintf(
    '<div class="snup_noplan">%s</div>',
    esc_html__('No planned posts yet.', 'snup-lang')
  );
}

$items = array();
foreach ($the_query->posts as $post) {

  $snuptext = get_post_meta( $post->ID, 'snuptext', true );
  if ( $snuptext && is_string( $snuptext ) ) {
    // turn linebreaks to <br>
    // @source https://www.php.net/manual/en/function.nl2br.php#73440
    $snuptext = str_replace(array("\r\n", "\r", "\n"), "<br />", $snuptext);
  } else {
    $snuptext="";
  }
  
  $items[] = sprintf(
    '<li>
      %s
      <div class="snup_title">%s</div>
      <div class="snup_text">%s</div>
      <div class="snup_published">%s</div>
      <div class="snup_time">%s</div>
    </li>',
    get_the_post_thumbnail($post),
    esc_html( $post->post_title ),
    esc_html( $snuptext ),
    esc_html__('Published', 'snup-lang'),
    get_the_time('d.m.Y H:i', $post)
  );
}

return sprintf('<ul>%s</ul>', implode('', $items));