Inside main template:

{% block step_1 %}
    <!-- Step 1: Item Details -->
    {% with wizard.step_1 as step %}
        {% decorate "item/wizard/ajax_step_decorator.html" %}
            {% localblock step_ready_js %}
                $(this).standardWizardStepFormBind(step, formId);
            {% endlocalblock %}
        {% enddecorate %}
    {% endwith %}
    <!-- / Step 1 -->
{% endblock %}

{% block step_2 %}
    <!-- Step 2: Category Select -->
    {% with wizard.step_2 as step %}
        {% decorate "item/wizard/ajax_step_decorator.html" %}
            {% localblock step_ready_js %}
                $(this).categorySelectLiveQueryActions();
            {% endlocalblock %}
        {% enddecorate %}
    {% endwith %}
    <!-- / Step 2 -->
{% endblock %}


Decorator: item/wizard/ajax_step_decorator.html

{% load conversation %}
{% load common_webdesign %}

<form id="{{ step.get_form_id }}" name="{{ step.get_form_name }}" action="{{ step.get_action }}" method="POST" class="standard-form">{% cid_hidden %}
    <div id="{{ step.get_div_id }}">
        <div id="{{ step.get_inner_div_id }}">
        {% if step.available %}
            {% localblock step_available_body %}
                {% include step.template_name %}
            {% endlocalblock %}
        {% else %}
            {% localblock step_unavailable_body %}
                {% include "item/wizard/disabled_step_block.html" %}
            {% endlocalblock %}
        {% endif %}
        </div>
    </div>
</form>

<script language="javascript">
    $(this).ready(function() {
        // Provides: step, formName, formId & disabledId
        {% include "item/wizard/step_javascript_vars.html" %}

        {% localblock step_ready_js %}{% endlocalblock %}
    });
</script>

Implementation (templatetags):

def decorate(parser, token):
    nodelist = parser.parse(('enddecorate',))
    parser.delete_first_token()

    try:
        tag_name, template_name = token.split_contents()
    except ValueError:
        raise TemplateSyntaxError, "%r tag requires one argument" % \
            token.contents.split()[0]

    decorateNode = DecorateNode(nodelist, parser.compile_filter(template_name))

    return decorateNode

class DecorateNode(Node):
    def __init__(self, nodelist, template_name):
        self.nodelist = nodelist
        self.template_name = template_name
        self.blocks = dict([(n.name, n) for n in nodelist.get_nodes_by_type(LocalBlockNode)])

    def render(self, context):
        template_name = self.template_name.resolve(context)
        t = get_template(template_name)
        context['localblock'] = self.blocks

        return t.render(context)

class LocalBlockNode(Node):
    def __init__(self, name, nodelist, parent=None):
        self.name, self.nodelist, self.parent = name, nodelist, parent

    def __repr__(self):
        return "<LocalBlock Node: %s. Contents: %r>" % (self.name, self.nodelist)

    def render(self, context):
        try:
            if self.name and 'localblock' in context:
                local_blocks = context['localblock']
                if local_blocks and self.name in local_blocks:
                    block = local_blocks[self.name]
                    return block.nodelist.render(context)
        except Except, e:
            logger.error("Failed to render LocalBlockNode")
            logger.error(e)
            raise

        # Failed to render contextual element, render this one:
        return self.nodelist.render(context)

def localblock(parser, token):
    """
    Define a block that can be overridden by child templates.
    """
    bits = token.contents.split()
    if len(bits) != 2:
        raise TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0]
    block_name = bits[1]
    nodelist = parser.parse(('endlocalblock', 'endlocalblock %s' % block_name))
    parser.delete_first_token()
    return LocalBlockNode(block_name, nodelist)

register.tag(localblock)
register.tag(decorate)