Update
I've created a paclet. Install with:
PacletInstall["https://github.com/carlwoll/DifferentialOperator/releases/download/0.1/DifferentialOperator-0.0.1.paclet"]
and load with:
<<DifferentialOperator`
Original post
Here's an approach I've been playing with that attempts to mimic traditional notation for these kinds of operators. The exposition is a little long, but the payoff is a very natural approach to handling operators.
DifferentialOperator
The first step is to create an operator form for derivatives that can be entered easily using the keyboard, and formats as expected. I call the operator form DifferentialOperator, and it has the following SubValues/UpValues:
DifferentialOperator[z__:x][f_] := D[f, z]
DifferentialOperator /: DifferentialOperator[z__:x]^n_Integer?Positive := Apply[
DifferentialOperator,
Flatten @ ConstantArray[{z}, n]
]
Here is an example:
L = DifferentialOperator[x, y]
L @ Exp[x y]
DifferentialOperator[x, y]
E^(x y) + E^(x y) x y
The above definition is a nice operator form, but the formatting is rather long, so I give DifferentialOperator a nice format below:
DifferentialOperator /: MakeBoxes[DifferentialOperator[], form_] := InterpretationBox[
"\[PartialD]", DifferentialOperator[]
]
DifferentialOperator /: MakeBoxes[DifferentialOperator[x__], form_] := With[
{sub = RowBox @ BoxForm`MakeInfixForm[{x},",", form]},
InterpretationBox[
SubscriptBox["\[PartialD]",sub],
DifferentialOperator[x]
]
]
Now, the operator L looks much more like the usual derivative operator:
L //TeXForm
$\partial _{x,y}$
Finally, typing DifferentialOperator is rather tedious and ugly, so I use InputAutoReplacements to streamline the input:
CurrentValue[EvaluationNotebook[], InputAutoReplacements] = {
"pd" -> TemplateBox[
{"\"\[PartialD]\""},
"Partial",
DisplayFunction -> (StyleBox[#, ShowStringCharacters->False]&),
InterpretationFunction -> (
RowBox[{"operator", "[", RowBox[{"DifferentialOperator","[","]"}],"]"}]&
),
Editable->False,
Selectable->False
],
ParentList
};
A few comments here:
a. I use a TemplateBox so that editing of the \[PartialD string is prevented.
b. I use "\"\[PartialD]\"" instead of just "\[PartialD]" so that input parsing works as expected.
c. I use ShowStringCharacters->False so that one doesn't see the quotes I added above.
d. The InterpretationFunction includes an operator wrapper that will be discussed later.
Here is a short animation showing me enter the OP operator into an input cell:

Composition
Differential operators don't commute with expressions, e.g., $\partial ⋅ x \neq x ⋅ \partial$, so I will use CenterDot for composition of operators.
I can't just use Composition because scalar operators have an implied Identity, but I can give CenterDot special rules to accommodate this. Here are the arithmetical rules:
(* arithmetic *)
CenterDot[___, 0, ___] = 0;
CenterDot[a_, c__] + CenterDot[b_, c__] ^:= CenterDot[a+b,c]
a_?scalarQ CenterDot[b_, c___] ^:= CenterDot[a b, c]
and the operator rules (SubValues):
SetAttributes[CenterDot,{Flat,OneIdentity}]
(* nested function application *)
CenterDot[a__, b_][x_] := CenterDot[a][CenterDot[b][x]]
(* function application *)
CenterDot[a_Plus][x_] := CenterDot[#][x]&/@a
CenterDot[a_?scalarQ][x_] := a x
CenterDot[a_?scalarQ b_?differentialQ][x_] := a CenterDot[b][x]
CenterDot[d_DifferentialOperator][x_] := d[x]
The operator wrapper
You may have noticed the operator wrapper in the above InterpretationFunction. Suppose one were to use $L = \partial + x$. Without the operator wrapper, the head would just be Plus, and applying L to a function L[f] would evaluate to Plus[DifferentialOperator[], x][f], and in order to have this evaluate further one would need to modify the System` symbol Plus (not a good idea). The operator wrapper automatically absorbs typical arithmetic operations so that arithmetic with an operator object will produce an operator object. This means that L[f] evaluates to an operator object, and we can give rules for operator in order to get the operator to act on a function. Here are the definitions for operator:
SetAttributes[operator, {Flat, OneIdentity}]
(* addition *)
operator[a_]+c_ ^:= operator[a+c]
(* scalar multiplication *)
c_?scalarQ operator[a_] ^:= operator[c a]
(* composition *)
operator[a_,b__] := operator[CenterDot[a,b]]
operator[a_]\[CenterDot]c_ ^:= operator[CenterDot[a,c]]
c_\[CenterDot]operator[a_] ^:= operator[CenterDot[c,a]]
(* power *)
operator /: operator[a_]^n_Integer := operator[CenterDot@@ConstantArray[a,n]]
(* subscripted nabla *)
Subscript[operator[DifferentialOperator[]], x__] ^:= operator[DifferentialOperator[x]]
(* utilities*)
scalarQ = FreeQ[DifferentialOperator];
differentialQ = Not @* scalarQ;
Some examples:

Notice how the head of every expression is operator. Now, we can give a definition for operator:
(* function application *)
operator[a_][x_] := CenterDot[a][x]
Finally, we need a format for operator, as we don't want to see it in the input or output:
operator/:MakeBoxes[operator[a__], form_]:=If[Length@Hold[a]>1,
StyleBox[MakeBoxes[CenterDot[a], form], Bold],
StyleBox[MakeBoxes[a, form], Bold]
]
I use Bold to indicate that the object is an operator:
L = Subscript[operator[DifferentialOperator[]], t,t] - 3 Subscript[operator[DifferentialOperator[]], t] + 2;
L //TeXForm
$\bf{\partial _{t,t}-3 \partial _t+2}$
Examples
That's it for the framework. Now, for the example in this question, we have:

Some other examples.
A commutator:

Operator arithmetic:

Question (15605):

Question (43775):

Question (20519):

I haven't included it here, but the next step is to perform simplifications of the CenterDot objects, in particular so that commutators can be defined.
TimesandPlus, so the symbols used for operators are still distinct from the usual ones, but more intuitive (I hope) than before. – Jens May 04 '12 at 07:06