Being able to store into the program was once considered much more important than it is now. Today we almost always load code, lock it read-only, and run it.
Even JIT compilers don't patch much. They mostly generate code into empty memory.
(There are exceptions. I think PyPy patches existing when a Python program replaces an existing function while running. You can do this in Python, but probably shouldn't.)
Von Neumann considered self-modifying code important for somewhat philosophical reasons related to his self-replicating automata ideas.
Previous pre-computer programmable machines, back to the Jacquard loom, stored programs in a completely different medium than the data. Plugboards, chains of Jacquard cards, cams, etc.
Von Neumann insisted that programs were just data and belonged in the same memory as the data. This was a conceptual advance. The hardware had to get there to make it work.
The next big innovation was the stack, in the modern sense. This came later than one might expect.
Note that there are at least two types of stack computers. There are ones with a return point and context stack, which is the C view of the world. And there are ones where working storage is on the stack, like Forth machines and early Burroughs machines. The first kind seems to have been invented for ALGOL in 1957, because ALGOL allowed recursion. Stacks made a lot of people nervous back then, because how much memory to allocate for the stack was unclear, and there wasn't much memory. FORTRAN disallowed recursion and thus did not need stacks and stack frames.
So storing into the program hung on in some architectures. UNIVAC 1107 and later mainframes had a Store Location Jump (SLJ) instruction. This stored the return address into the beginning of a subroutine. Not into a stack frame; there was no stack by default. Into the first word of the subroutine's code. For non-recursive non-concurrent code, it worked.[1] But it was used less over time, with different constructs used instead.
Program in the same memory as data, yes. Program can create more program, yes. Program modifies itself while running, not so good. Index registers eliminate most needs for the third case.
[1] https://www.fourmilab.ch/documents/univac/instructions.html