Streamlining a loop with a bunch of conditions
I'm not sure if this is better or not but one thing I'd do here is to set some defaults in my include. This also means you don't need to worry about checking whether it's defined or not. You're just checking whether it's true.

{% set options = {
    author: true,
    badge: true,
    date: true,
    magnify: true,
    meta: true,
    thumbnail: true,
} | merge(cardOptions | default({})) %}

&lt;div class="card"&gt;

    {% if options.badge %}
        &lt;div class="badge"&gt;
            &lt;img src="/assets/images/icon-new.svg" height="14px" width="14px" alt="New!"&gt;
        &lt;/div&gt;
    {% endif %}

    {% if options.thumbnail %}
        &lt;a href="#"&gt;
            &lt;img src="http://placehold.it/320x210" 
                srcset="http://placehold.it/640x420 750w, 
                     http://placehold.it/320x210 280w" 
                sizes="100%"
                alt=""
                class="tn"&gt;
        &lt;/a&gt;
    {% endif %}

    &lt;article&gt;
        &lt;h2&gt;&lt;a href="#"&gt;Heading Goes in Here&lt;/a&gt;&lt;/h2&gt;

        {% if options.meta %}

            &lt;footer class="meta"&gt;
                {% if options.date %}
                    {% include "_modules/relative-date" %} 
                {% endif %}
                {% if options.author %}
                    by &lt;a href="#" rel="author"&gt;John Doe&lt;/a&gt;
                {% endif %}
            &lt;/footer&gt;

        {% endif %}

    &lt;/article&gt;
&lt;/div&gt;


Then when I use this include I can pass in an object of options that could overide those defaults. But I only need to pass in values that need to change the defaults. For example here I can set meta to false but can leave all the others to be handled by the default:

{% set cardOptions = {
    meta: false
} %}

{% include "_modules/card" with cardOptions %}


You said this would be included within an entries loop. You could do this in that case:

{% set options = {
    entry: false,
    author: true,
    badge: true,
    date: true,
    magnify: true,
    meta: true,
    thumbnail: true,
} | merge(cardOptions | default({})) %}

{# Wrap the whole card in a conditional #}
{% if options.entry %}
   // Card goes here
{% endif %}


And then in your entries loop you'd do:

{% for entry in entries %}

    {% set cardOptions = {
        entry: entry
    } %}

    {% include "_modules/card" with cardOptions only %}
{% endfor %}


I'd probably use the only option on the include tag to avoid stuff leaking in.

I've also played with options such as:

{% set cardOptions = {
    styleGuide: true
} %}


In my include this option will have a false default I'll have a conditional that checks for it being true and if so it'll ignore any dynamic content and instead I'll output an example of the module with fake content. It's good for testing and for keeping a library of modules.

You could also consider a macro that wraps your include tag. I gave a similar example in a blog post not long ago: Using macros to improve consistency in your Craft CMS templates

{% macro module(type, options = {}) %}
    {% include '_modules/' ~ type with options only %}
{% endmacro %}


And then in your template you'd do something like:

{% set cardOptions = {
    entry: entry,
    meta: false
} %}

{{ module('card', cardOptions) }}


Dunno if any of that helps!